github/copilot-sdk · error · InvalidOperationException

Copilot runtime wrapper not found at

Error message

Copilot runtime wrapper not found at '{wrapper}'.

What it means

ValidateRuntimePair checks that a Copilot runtime wrapper file exists before launching it. The wrapper executable (e.g. the Node script/entrypoint that loads runtime.node) was not found at the configured path, so launch is refused.

Solutions

  1. Verify the wrapper path in your options points to an existing file (use an absolute path).
  2. Reinstall/restore the Copilot runtime assets (nuget restore / package reinstall) so the wrapper is present.
  3. Check for typos, wrong casing, or pointing at a directory instead of the wrapper file.
  4. If the path is derived at runtime, resolve it relative to AppContext.BaseDirectory or the assembly location instead of the current working directory.

Example fix

// before
options.WrapperPath = "copilot-runtime/wrapper.js"; // relative to CWD

// after
options.WrapperPath = Path.Combine(AppContext.BaseDirectory, "copilot-runtime", "wrapper.js");
Defensive patterns

Strategy: validation

Validate before calling

if (options.WrapperPath is null || !File.Exists(options.WrapperPath))
    throw new FileNotFoundException($"Copilot runtime wrapper not found at '{options.WrapperPath}'");

Type guard

static bool WrapperExists(string? p) => p is { Length: > 0 } && File.Exists(p);

Try / catch

try
{
    await client.StartAsync();
}
catch (InvalidOperationException ex) when (ex.Message.Contains("wrapper not found"))
{
    logger.LogError(ex, "Runtime wrapper missing at configured path");
}

Prevention

When it happens

Trigger: File.Exists(wrapper) is false at Client.cs:2502 when the client validates the runtime wrapper path during launch setup (ValidateRuntimePair), typically from a path supplied via CopilotClientOptions.

Common situations: Typo or wrong casing in the wrapper path in options; pointing at a directory instead of the wrapper file; the runtime assets were never downloaded/installed; the package was partially copied and the wrapper omitted; path computed relative to a working directory that differs at runtime.

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/a59b846c9be97cb1. Report an issue: GitHub.

Appendix: source

Thrown at dotnet/src/Client.cs:2502

        var directory = Path.GetDirectoryName(searchedWrapper)!;
        var runtimeNode = Path.Combine(directory, "runtime.node");
        var explicitCliMarker = Path.Combine(directory, ExplicitBundledCliMarker);
        if (!File.Exists(searchedWrapper)
            && !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)
            {

View on GitHub (pinned to cd8cf15dc3)