{"record":{"id":"1a92b03ae43b7cdc","repo":"github/copilot-sdk","slug":"sruntimenodehash-must-be-a-sha-256-hash-d-bytes","errorCode":null,"errorMessage":"%sRuntimeNodeHash must be a SHA-256 hash (%d bytes), got %d bytes","messagePattern":"(.+?)RuntimeNodeHash must be a SHA-256 hash \\((.+?) bytes\\), got (.+?) bytes","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/internal/embeddedcli/embeddedcli.go","lineNumber":428,"sourceCode":"\t\t\treturn err\n\t\t}\n\t}\n\truntimeAssetsInstalled = true\n\treturn nil\n}\n\nfunc validateRuntimePairConfig(wrapper io.Reader, wrapperHash []byte, node io.Reader, nodeHash []byte, prefix string) {\n\tif (wrapper == nil) != (node == nil) {\n\t\tpanic(prefix + \"RuntimeExecutable and \" + prefix + \"RuntimeNode must be provided together\")\n\t}\n\tif wrapper == nil {\n\t\treturn\n\t}\n\tif len(wrapperHash) != sha256.Size {\n\t\tpanic(fmt.Sprintf(\"%sRuntimeExecutableHash must be a SHA-256 hash (%d bytes), got %d bytes\", prefix, sha256.Size, len(wrapperHash)))\n\t}\n\tif len(nodeHash) != sha256.Size {\n\t\tpanic(fmt.Sprintf(\"%sRuntimeNodeHash must be a SHA-256 hash (%d bytes), got %d bytes\", prefix, sha256.Size, len(nodeHash)))\n\t}\n}\n\nfunc installRuntimePair(installDir string) (string, error) {\n\tnodePath := filepath.Join(installDir, \"runtime.node\")\n\tif err := installVerifiedFile(nodePath, config.RuntimeNode, config.RuntimeNodeHash, 0644, \"runtime.node\"); err != nil {\n\t\treturn \"\", err\n\t}\n\twrapperPath := filepath.Join(installDir, runtimeExecutableName())\n\tif err := installVerifiedFile(wrapperPath, config.RuntimeExecutable, config.RuntimeExecutableHash, 0755, \"runtime wrapper\"); err != nil {\n\t\treturn \"\", err\n\t}\n\treturn wrapperPath, nil\n}\n\nfunc installVerifiedFile(path string, reader io.Reader, expectedHash []byte, mode os.FileMode, label string) error {\n\tif _, err := os.Stat(path); err == nil {\n\t\texistingHash, err := hashFile(path)","sourceCodeStart":410,"sourceCodeEnd":446,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/go/internal/embeddedcli/embeddedcli.go#L410-L446","documentation":"validateRuntimePairConfig performs the same 32-byte SHA-256 length check for the runtime node library's hash as it does for the wrapper: when both pair members are set but the node hash has the wrong length, Setup panics naming the platform prefix (e.g. \"LinuxMuslRuntimeNodeHash\"). This guarantees installRuntimePair can verify runtime.node against its digest after writing it.","triggerScenarios":"Calling Setup with the runtime pair present but cfg.LinuxMuslRuntimeNodeHash (or the default RuntimeNodeHash) empty, hex-encoded, or otherwise not exactly 32 raw bytes.","commonSituations":"Hash generated by a different tool (base64 or hex text); field copied from the executable hash but truncated/emptied during a refactor; CI step that emits the digest with a newline-included string converted to bytes.","solutions":["Convert the hex digest with hex.DecodeString so the field holds exactly 32 bytes.","Recompute: h := sha256.Sum256(nodeBytes); cfg.LinuxMuslRuntimeNodeHash = h[:].","Trim whitespace/newlines from the digest string before decoding; assert len(raw) == sha256.Size in the build step."],"exampleFix":"// before\ncfg.LinuxMuslRuntimeNodeHash = []byte(strings.TrimSpace(digestHex)) // 64 bytes\n\n// after\nraw, _ := hex.DecodeString(strings.TrimSpace(digestHex))\ncfg.LinuxMuslRuntimeNodeHash = raw // 32 bytes","handlingStrategy":"validation","validationCode":"func validNodeHash(h []byte) bool { return len(h) == sha256.Size }","typeGuard":"func isSHA256(b []byte) bool { return len(b) == sha256.Size }","tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        if s, ok := r.(string); ok && strings.Contains(s, \"RuntimeNodeHash must be a SHA-256 hash\") {\n            log.Fatalf(\"bad runtime node hash: %s\", s)\n        }\n        panic(r)\n    }\n}()","preventionTips":["Decode hex digests to 32 raw bytes before storing them in Config.","Trim whitespace from digests produced by shell/CI steps before decoding.","Validate all hash fields (executable and node) in a pre-Setup sanity test."],"tags":["go","panic","sha256","checksum","config-validation"],"backgroundTag":"invalid-argument-format","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}