github/copilot-sdk · error
%sRuntimeExecutable and %sRuntimeNode must be provided…
Error message
%sRuntimeExecutable and %sRuntimeNode must be provided together
What it means
validateRuntimePairConfig requires the platform runtime wrapper executable and the runtime node library to be configured together: one without the other is an invalid state because the installed runtime is only coherent as a pair. Setup panics when exactly one of (wrapper, node) is nil. The check runs for every configured platform prefix (e.g. "LinuxMusl") and for the default pair.
Solutions
- Provide both fields for the platform: set cfg.LinuxMuslRuntimeNode (and its hash) whenever cfg.LinuxMuslRuntimeExecutable is set.
- If the platform's runtime is intentionally absent, clear both fields so the pair is nil/nil and the validator returns early.
- Check your build embedding (go:embed / ldflags injection) so both assets for each platform are compiled in.
Example fix
// before cfg.LinuxMuslRuntimeExecutable = wrapperReader cfg.LinuxMuslRuntimeExecutableHash = wrapperHash // LinuxMuslRuntimeNode forgotten // after cfg.LinuxMuslRuntimeExecutable = wrapperReader cfg.LinuxMuslRuntimeExecutableHash = wrapperHash cfg.LinuxMuslRuntimeNode = nodeReader cfg.LinuxMuslRuntimeNodeHash = nodeHash
Defensive patterns
Strategy: validation
Validate before calling
func pairComplete(exec, node io.Reader) bool { return (exec == nil) == (node == nil) } Type guard
func hasRuntimePair(cfg Config) bool {
return (cfg.LinuxMuslRuntimeExecutable == nil) == (cfg.LinuxMuslRuntimeNode == nil)
} Try / catch
defer func() {
if r := recover(); r != nil {
if s, ok := r.(string); ok && strings.Contains(s, "must be provided together") {
log.Fatalf("runtime pair misconfigured: %s", s)
}
panic(r)
}
}() Prevention
- Set both pair fields together in a single constructor/helper function for the platform.
- Audit go:embed directives so every platform embeds both the executable and the node library.
- Add a unit test that runs Setup with your production Config in CI.
When it happens
Trigger: Calling Setup with cfg.LinuxMuslRuntimeExecutable set but cfg.LinuxMuslRuntimeNode nil (or vice versa); partially populating a Config struct and forgetting the sibling field; build tags injecting only one of the two embedded assets.
Common situations: Cross-compiling for a platform where only one asset was embedded into the binary; hand-edited config code that set the executable but not the node library; conditional builds that strip one resource.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- must be a SHA-256 hash ( bytes), got bytes
- %sRuntimeExecutableHash must be a SHA-256 hash
- %sRuntimeNodeHash must be a SHA-256 hash
- SessionFS.InitialWorkingDirectory is required
- Env is not supported with InProcessConnection: the…
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/f1213580c312de79.
Report an issue: GitHub.
Appendix: source
Thrown at go/internal/embeddedcli/embeddedcli.go:419
return fmt.Errorf("reading runtime asset %q: %w", header.Name, err)
}
path := filepath.Join(installDir, clean)
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
return fmt.Errorf("creating runtime asset directory: %w", err)
}
hash := sha256.Sum256(content)
mode := os.FileMode(header.Mode & 0777)
if err := installVerifiedFile(path, bytes.NewReader(content), hash[:], mode, "runtime asset"); err != nil {
return err
}
}
runtimeAssetsInstalled = true
return nil
}
func validateRuntimePairConfig(wrapper io.Reader, wrapperHash []byte, node io.Reader, nodeHash []byte, prefix string) {
if (wrapper == nil) != (node == nil) {
panic(prefix + "RuntimeExecutable and " + prefix + "RuntimeNode must be provided together")
}
if wrapper == nil {
return
}
if len(wrapperHash) != sha256.Size {
panic(fmt.Sprintf("%sRuntimeExecutableHash must be a SHA-256 hash (%d bytes), got %d bytes", prefix, sha256.Size, len(wrapperHash)))
}
if len(nodeHash) != sha256.Size {
panic(fmt.Sprintf("%sRuntimeNodeHash must be a SHA-256 hash (%d bytes), got %d bytes", prefix, sha256.Size, len(nodeHash)))
}
}
func installRuntimePair(installDir string) (string, error) {
nodePath := filepath.Join(installDir, "runtime.node")
if err := installVerifiedFile(nodePath, config.RuntimeNode, config.RuntimeNodeHash, 0644, "runtime.node"); err != nil {
return "", err
}
wrapperPath := filepath.Join(installDir, runtimeExecutableName())View on GitHub (pinned to cd8cf15dc3)