Skip to content

Load only assemblies from closure. - #11965

Merged
Nikolay Rovinskiy (nick863) merged 1 commit into
mainfrom
nirovins/load_closure_only
Sep 15, 2026
Merged

Nikolay Rovinskiy (nick863) merged 1 commit into
mainfrom
nirovins/load_closure_only

Conversation

@nick863

@nick863 Nikolay Rovinskiy (nick863) commented Sep 14, 2026

Copy link
Copy Markdown
Member

During package generation the NuGetPackage resolver is trying to load all available packages, including the incompatible. In this PR we are limiting loading packages to the project dependencies.

This problem results in cryptic failure if NuGet cache folder contains incompatible packages. Here is an example

<long list of classes and methods, which cannot be loaded>
Could not load type 'Microsoft.CodeAnalysis.Host.IRecoverableSyntaxTree`1' from assembly 'Microsoft.CodeAnalysis.Workspaces, Version=4.8.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'.
Method not found: 'System.Threading.Tasks.Task`1<Microsoft.CodeAnalysis.Document> Microsoft.CodeAnalysis.CodeCleanup.Providers.ICodeCleanupProvider.CleanupAsync(Microsoft.CodeAnalysis.Document, System.Collections.Immutable.ImmutableArray`1<Microsoft.CodeAnalysis.Text.TextSpan>, System.Threading.CancellationToken)'.
Method not found: 'System.Threading.Tasks.Task`1<Microsoft.CodeAnalysis.Document> Microsoft.CodeAnalysis.CodeCleanup.Providers.ICodeCleanupProvider.CleanupAsync(Microsoft.CodeAnalysis.Document, System.Collections.Immutable.ImmutableArray`1<Microsoft.CodeAnalysis.Text.TextSpan>, System.Threading.CancellationToken)'.
   at System.Reflection.RuntimeModule.GetTypes(QCallModule module, ObjectHandleOnStack retTypes)
   at System.Reflection.RuntimeModule.GetDefinedTypes()
   at System.Composition.Hosting.ContainerConfiguration.<>c.<WithAssemblies>b__16_0(Assembly a)
   at System.Linq.Enumerable.SelectManySingleSelectorIterator`2.MoveNext()
   at System.Composition.TypedParts.TypedPartExportDescriptorProvider..ctor(IEnumerable`1 types, AttributedModelProvider attributeContext)
   at System.Composition.Hosting.ContainerConfiguration.CreateContainer()
   at Microsoft.CodeAnalysis.Host.Mef.MefHostServices.Create(IEnumerable`1 assemblies)
   at Microsoft.CodeAnalysis.Host.Mef.MefHostServices.get_DefaultHost()
   at Microsoft.CodeAnalysis.AdhocWorkspace..ctor()
   at Microsoft.TypeSpec.Generator.GeneratedCodeWorkspace.CreateGeneratedCodeProject() in /mnt/vss/_work/1/s/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/PostProcessing/GeneratedCodeWorkspace.cs:line 175
   at System.Threading.Tasks.Task`1.InnerInvoke()
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location ---
   at Microsoft.TypeSpec.Generator.GeneratedCodeWorkspace.Create(Boolean isCustomCodeProject) in /mnt/vss/_work/1/s/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/PostProcessing/GeneratedCodeWorkspace.cs:line 191
   at Microsoft.TypeSpec.Generator.CSharpGen.ExecuteAsync() in /mnt/vss/_work/1/s/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/CSharpGen.cs:line 48
   at Microsoft.TypeSpec.Generator.GeneratorRunner.RunAsync(CommandLineOptions options) in /mnt/vss/_work/1/s/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/StartUp/GeneratorRunner.cs:line 17

This error is machine specific, because on different environment there was single issue in the attempt to load System.Range from assembly 'Microsoft.CodeAnalysis.Workspaces, Version=4.8.0.0.

In all the cases the issue happens while AdhocWorkspace creation. It creates DefaultHostServices, which loads the assemblies, resulting in crash above.

@pkg-pr-new

pkg-pr-new Bot commented Sep 14, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@typespec/http-client-csharp@11965

commit: f253682

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Unbounded dependency ranges may be omitted from the closure, preventing valid external types from loading.

Pull request overview

Limits NuGet assembly resolution to the project's dependency closure.

Changes:

  • Removes fallback probing of arbitrary cached package versions.
  • Restricts assembly lookup to closure-recorded versions.
File summaries
File Summary
packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Utilities/NugetAssemblyResolver.cs Restricts probing to dependency-closure assemblies; unbounded dependency ranges still require handling.
Review details

Suppressed comments (2)

packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Utilities/NugetAssemblyResolver.cs:359

  • WalkPackage only records dependencies when VersionRange.MinVersion is non-null (lines 214-220), so a nuspec dependency declared without a lower bound (<dependency id="..." /> or *) is omitted even though it is part of the package closure. After this fallback is deleted, the resolver never probes that dependency and a valid external type whose base/interface is in that package fails to load; derive the closure from the project's resolved assets (or otherwise pin unbounded ranges to their selected versions) before enforcing closure-only probing.

This issue also appears on line 356 of the same file.

            if (assemblyPath == null)
            {
                _debug($"Could not locate dependency assembly '{simpleName}' under '{_globalPackagesFolder}'.");
                return null;

packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Utilities/NugetAssemblyResolver.cs:359

  • With this fallback removed, Resolve now returns before reading a cached assembly unless RegisterPackageClosure has populated _closureVersions. The existing NugetAssemblyResolverTests.Resolve_ReturnsNullAndLogsWhenAssemblyCannotBeLoaded constructs the resolver without registering a closure and expects the invalid cached file to be loaded far enough to log Failed to load dependency assembly; this now logs Could not locate dependency assembly and fails. Update that test/call contract and add explicit closure-only coverage in this PR.
            if (assemblyPath == null)
            {
                _debug($"Could not locate dependency assembly '{simpleName}' under '{_globalPackagesFolder}'.");
                return null;
  • Files reviewed: 1/1 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@github-actions

Copy link
Copy Markdown
Contributor

No changes needing a change description found.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved closure/version handling issues and a failing test setup block approval.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (2)

packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Utilities/NugetAssemblyResolver.cs:359

  • Removing the fallback exposes that RegisterPackageClosure records each dependency's VersionRange.MinVersion (see NugetAssemblyResolver.cs:214-220), not the version NuGet actually selected in project.assets.json. For a dependency declared as >= 1.0.0 but resolved by the project to 2.0.0, FindPackageAssemblyInVersion now probes only 1.0.0 and returns null when that version is absent, so valid external types fail to load. Build the closure from the resolved asset graph (or otherwise constrain probing to the selected project version) before removing this fallback, and cover a minimum-version-below-selected-version case.
            if (assemblyPath == null)
            {
                _debug($"Could not locate dependency assembly '{simpleName}' under '{_globalPackagesFolder}'.");
                return null;

packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Utilities/NugetAssemblyResolver.cs:359

  • After removing the fallback, Probe can resolve a package only when _closureVersions contains its simple name. However, WalkPackage only adds dependencies whose VersionRange.MinVersion is non-null (NugetAssemblyResolver.cs:216-220), so a valid unbounded nuspec dependency such as <dependency id="B" /> is omitted even when NuGet restored B in the project's closure. External types inheriting from or implementing a type in B will now fail to load; the closure needs to be populated from the resolved project assets (or otherwise retain unbounded dependencies) before this fallback is removed.
            if (assemblyPath == null)
            {
                _debug($"Could not locate dependency assembly '{simpleName}' under '{_globalPackagesFolder}'.");
                return null;
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Lite

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The resolver can fail to locate packages when the selected version differs from the dependency range minimum.

Get a fresh assessment by requesting another Copilot review.

Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Lite

@nick863
Nikolay Rovinskiy (nick863) added this pull request to the merge queue Sep 15, 2026
Merged via the queue into main with commit 6852baf Sep 15, 2026
31 checks passed
@nick863
Nikolay Rovinskiy (nick863) deleted the nirovins/load_closure_only branch September 15, 2026 23:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

emitter:client:csharp Issue for the C# client emitter: @typespec/http-client-csharp

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants