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

  1. Provide both fields for the platform: set cfg.LinuxMuslRuntimeNode (and its hash) whenever cfg.LinuxMuslRuntimeExecutable is set.
  2. If the platform's runtime is intentionally absent, clear both fields so the pair is nil/nil and the validator returns early.
  3. 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

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


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)