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
- Delete the empty file(s) and reinstall/redownload the runtime package so both files are non-empty.
- Re-run the build/publish step that copies the runtime assets, checking for disk-space errors.
- Verify file sizes on disk (`ls -l`) before launching; restore the real binary if LFS placeholders were committed.
- 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
- Check for disk-full/interrupted-copy errors during build and publish.
- Restore real binaries when git LFS placeholders appear.
- Add file-size or hash verification to the deployment pipeline.
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
- Copilot runtime wrapper at
- Request cancelled by runtime
- copilot_runtime_host_start failed
- at is empty.
- Copilot runtime wrapper not found at
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)