github/copilot-sdk · error · InvalidOperationException
Copilot runtime wrapper at
Error message
Copilot runtime wrapper at '{wrapper}' is missing its adjacent runtime.node at '{runtimeNode}'. What it means
The Copilot runtime wrapper exists, but its required adjacent `runtime.node` native module (expected in the same directory) is missing. The wrapper cannot run without this companion binary, so validation throws before launch.
Solutions
- Ensure runtime.node sits in the same directory as the wrapper (copy both together).
- Fix build/packaging globs so *.node files are included in output (e.g. csproj CopyToOutputDirectory for native assets).
- Reinstall the runtime package if the native module was deleted or quarantined by antivirus.
- Verify with `ls <wrapper-dir>` that both wrapper and runtime.node exist before launching.
Example fix
// before (csproj) <None Include="runtime\wrapper.js" CopyToOutputDirectory="PreserveNewest" /> // after (csproj) <None Include="runtime\**\*" CopyToOutputDirectory="PreserveNewest" /> <!-- includes runtime.node -->
Defensive patterns
Strategy: validation
Validate before calling
var wrapperDir = Path.GetDirectoryName(Path.GetFullPath(options.WrapperPath!));
if (!File.Exists(Path.Combine(wrapperDir!, "runtime.node")))
throw new FileNotFoundException($"runtime.node missing next to wrapper at '{wrapperDir}'"); Type guard
static bool RuntimePairExists(string? wrapper) =>
wrapper is { Length: > 0 } &&
File.Exists(wrapper) &&
File.Exists(Path.Combine(Path.GetDirectoryName(Path.GetFullPath(wrapper))!, "runtime.node")); Try / catch
try
{
await client.StartAsync();
}
catch (InvalidOperationException ex) when (ex.Message.Contains("runtime.node"))
{
logger.LogError(ex, "runtime.node missing adjacent to the runtime wrapper");
} Prevention
- Copy the whole runtime directory, never individual files.
- Include *.node files in packaging globs (csproj None/CopyToOutputDirectory).
- Check deployment tooling/antivirus logs for stripped native binaries.
When it happens
Trigger: File.Exists(runtimeNode) is false at Client.cs:2506, where runtimeNode = <wrapper directory>/runtime.node, during ValidateRuntimePair prior to launching the runtime.
Common situations: Copying only the wrapper file when distributing the app and forgetting runtime.node; packaging rules (e.g. csproj/pack globs) that exclude *.node native binaries; antivirus or deployment tooling stripping native binaries; a wrapper copied out of its original directory.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- Copilot runtime wrapper not found at
- Copilot runtime wrapper and adjacent runtime.node must both…
- In-process FFI runtime library not found at
- file not found in tarball
- Request cancelled by runtime
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/9330afeaa3dd0723.
Report an issue: GitHub.
Appendix: source
Thrown at dotnet/src/Client.cs:2506
&& !File.Exists(runtimeNode)
&& File.Exists(explicitCliMarker)
&& GetBundledCliPath(out _) is { } explicitCli)
{
return new RuntimeLaunch(explicitCli, "Bundled explicit CLI");
}
return ValidateRuntimePair(searchedWrapper, "Bundled runtime");
}
private static RuntimeLaunch ValidateRuntimePair(string wrapper, string source)
{
var runtimeNode = Path.Combine(Path.GetDirectoryName(Path.GetFullPath(wrapper))!, "runtime.node");
if (!File.Exists(wrapper))
{
throw new InvalidOperationException($"Copilot runtime wrapper not found at '{wrapper}'.");
}
if (!File.Exists(runtimeNode))
{
throw new InvalidOperationException(
$"Copilot runtime wrapper at '{wrapper}' is missing its adjacent runtime.node at '{runtimeNode}'.");
}
if (new FileInfo(wrapper).Length == 0 || new FileInfo(runtimeNode).Length == 0)
{
throw new InvalidOperationException("Copilot runtime wrapper and adjacent runtime.node must both be non-empty.");
}
#if NET8_0_OR_GREATER
if (!OperatingSystem.IsWindows())
{
var mode = File.GetUnixFileMode(wrapper);
const UnixFileMode executeBits =
UnixFileMode.UserExecute | UnixFileMode.GroupExecute | UnixFileMode.OtherExecute;
if ((mode & executeBits) == 0)
{
File.SetUnixFileMode(wrapper, mode | executeBits);
}
}
#endifView on GitHub (pinned to cd8cf15dc3)