Skip to content

Commit f116493

Browse files
committed
fix(roslyn): install missing System.Runtime.CompilerServices.Unsafe and surface inner errors
The RoslynInstaller downloads only 4 NuGet packages but Microsoft.CodeAnalysis 4.12.0 on netstandard2.0 also references System.Runtime.CompilerServices.Unsafe v6.0.0.0, which is NOT what Unity ships (Unity bundles v4.x). The reference is unresolved at runtime, so Roslyn's StringTable static cctor throws FileNotFoundException, which in turn poisons CSharpSyntaxTree's cctor: every parse / compile attempt then throws TypeInitializationException. The error is invisible because RoslynCompiler.Compile's catch block only logs e.Message, and for TargetInvocationException that string is the generic "Exception has been thrown by the target of an invocation." — the real cause in InnerException is silently dropped. Repro: 1. Trigger Tools > MCP for Unity > Install Roslyn on a fresh project. 2. Ask the MCP execute_code tool to compile any Roslyn-only snippet. 3. Observe: "Compilation failed: Roslyn compilation error: Exception has been thrown by the target of an invocation." — with no further detail. 4. Drilling via reflection reveals: TypeInitializationException for CSharpSyntaxTree └─ TypeInitializationException for Roslyn.Utilities.StringTable └─ FileNotFoundException: Could not load file or assembly 'System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0' Fix: * RoslynInstaller.NuGetEntries: add the missing dependency so a fresh install drops all 5 DLLs into Assets/Plugins/Roslyn/. * RoslynCompiler.Compile catch: walk the InnerException chain so a future bootstrap regression surfaces the actual cause (type + message) instead of the generic invocation wrapper. Verified locally: after dropping System.Runtime.CompilerServices.Unsafe.dll v6 into the plugins folder and forcing a domain reload, the execute_code tool compiles C# 7+ snippets via the Roslyn backend successfully.
1 parent a2a5edf commit f116493

2 files changed

Lines changed: 15 additions & 5 deletions

File tree

MCPForUnity/Editor/Setup/RoslynInstaller.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,14 @@ public static class RoslynInstaller
1313

1414
private static readonly (string packageId, string version, string dllPath, string dllName)[] NuGetEntries =
1515
{
16-
("microsoft.codeanalysis.common", "4.12.0", "lib/netstandard2.0/Microsoft.CodeAnalysis.dll", "Microsoft.CodeAnalysis.dll"),
17-
("microsoft.codeanalysis.csharp", "4.12.0", "lib/netstandard2.0/Microsoft.CodeAnalysis.CSharp.dll","Microsoft.CodeAnalysis.CSharp.dll"),
18-
("system.collections.immutable", "8.0.0", "lib/netstandard2.0/System.Collections.Immutable.dll", "System.Collections.Immutable.dll"),
19-
("system.reflection.metadata", "8.0.0", "lib/netstandard2.0/System.Reflection.Metadata.dll", "System.Reflection.Metadata.dll"),
16+
("microsoft.codeanalysis.common", "4.12.0", "lib/netstandard2.0/Microsoft.CodeAnalysis.dll", "Microsoft.CodeAnalysis.dll"),
17+
("microsoft.codeanalysis.csharp", "4.12.0", "lib/netstandard2.0/Microsoft.CodeAnalysis.CSharp.dll", "Microsoft.CodeAnalysis.CSharp.dll"),
18+
("system.collections.immutable", "8.0.0", "lib/netstandard2.0/System.Collections.Immutable.dll", "System.Collections.Immutable.dll"),
19+
("system.reflection.metadata", "8.0.0", "lib/netstandard2.0/System.Reflection.Metadata.dll", "System.Reflection.Metadata.dll"),
20+
// Transitive dep of Microsoft.CodeAnalysis.* on netstandard2.0. Without it, Roslyn's StringTable
21+
// static cctor throws FileNotFoundException for v6.0.0.0 and every Roslyn entry point fails to
22+
// initialize. Unity ships a v4.x of this assembly which does NOT satisfy the v6 reference.
23+
("system.runtime.compilerservices.unsafe","6.0.0", "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll", "System.Runtime.CompilerServices.Unsafe.dll"),
2024
};
2125

2226
public static bool IsInstalled()

MCPForUnity/Editor/Tools/ExecuteCode.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,13 @@ public static Assembly Compile(string source, string[] assemblyPaths, out List<s
672672
}
673673
catch (Exception e)
674674
{
675-
errors.Add($"Roslyn compilation error: {e.Message}");
675+
// Walk to the deepest cause: TargetInvocationException (and friends) wrap the real
676+
// failure inside .InnerException, and reporting only e.Message hides everything
677+
// useful (e.g. a missing transitive dep manifests as the generic "Exception has been
678+
// thrown by the target of an invocation.").
679+
Exception root = e;
680+
while (root.InnerException != null) root = root.InnerException;
681+
errors.Add($"Roslyn compilation error: {root.GetType().Name}: {root.Message}");
676682
return null;
677683
}
678684
}

0 commit comments

Comments
 (0)