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

  1. Ensure runtime.node sits in the same directory as the wrapper (copy both together).
  2. Fix build/packaging globs so *.node files are included in output (e.g. csproj CopyToOutputDirectory for native assets).
  3. Reinstall the runtime package if the native module was deleted or quarantined by antivirus.
  4. 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

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


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);
            }
        }
#endif

View on GitHub (pinned to cd8cf15dc3)