github/copilot-sdk · error · InvalidOperationException

Copilot runtime wrapper and adjacent runtime.node must both…

Error message

Copilot runtime wrapper and adjacent runtime.node must both be non-empty.

What it means

Both the runtime wrapper and its adjacent runtime.node exist, but at least one of them is a zero-byte file. An empty wrapper or native module is corrupt (failed download/copy), so the client throws instead of attempting a doomed launch.

Solutions

  1. Delete the empty file(s) and reinstall/redownload the runtime package so both files are non-empty.
  2. Re-run the build/publish step that copies the runtime assets, checking for disk-space errors.
  3. Verify file sizes on disk (`ls -l`) before launching; restore the real binary if LFS placeholders were committed.
  4. Add an integrity check (size/hash) to your deployment pipeline for native runtime assets.

Example fix

// before: zero-byte runtime.node from a failed copy
File.Copy(srcWrapper, destWrapper); // runtime.node copy failed silently

// after: copy both and validate
File.Copy(srcWrapper, destWrapper, overwrite: true);
File.Copy(srcRuntimeNode, destRuntimeNode, overwrite: true);
if (new FileInfo(destRuntimeNode).Length == 0) throw new IOException("runtime.node copy produced an empty file");
Defensive patterns

Strategy: validation

Validate before calling

var w = new FileInfo(options.WrapperPath!);
var n = new FileInfo(Path.Combine(w.DirectoryName!, "runtime.node"));
if (w.Length == 0 || n.Length == 0)
    throw new IOException("Runtime wrapper/runtime.node must both be non-empty; reinstall the runtime");

Type guard

static bool RuntimeAssetsValid(string? wrapper) =>
    wrapper is { Length: > 0 } && File.Exists(wrapper) &&
    new FileInfo(wrapper).Length > 0 &&
    File.Exists(Path.Combine(Path.GetDirectoryName(Path.GetFullPath(wrapper))!, "runtime.node")) &&
    new FileInfo(Path.Combine(Path.GetDirectoryName(Path.GetFullPath(wrapper))!, "runtime.node")).Length > 0;

Try / catch

try
{
    await client.StartAsync();
}
catch (InvalidOperationException ex) when (ex.Message.Contains("must both be non-empty"))
{
    logger.LogError(ex, "Zero-byte runtime asset detected; reinstall the Copilot runtime");
}

Prevention

When it happens

Trigger: new FileInfo(wrapper).Length == 0 || new FileInfo(runtimeNode).Length == 0 at Client.cs:2511 during ValidateRuntimePair.

Common situations: Interrupted download or copy that left a 0-byte file; disk-full during build/publish; a git LFS or packaging step that replaced the binary with a placeholder; filesystem corruption after a crash.

Related errors


AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09). Data as JSON: /api/errors/b76cb015307fc23e. Report an issue: GitHub.

Appendix: source

Thrown at dotnet/src/Client.cs:2511

        }
        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
        return new RuntimeLaunch(wrapper, source);
    }

    private sealed record RuntimeLaunch(string Executable, string Source);

View on GitHub (pinned to cd8cf15dc3)