{"record":{"id":"59696deb731f0046","repo":"github/copilot-sdk","slug":"sruntimeexecutablehash-must-be-a-sha-256-hash-d","errorCode":null,"errorMessage":"%sRuntimeExecutableHash must be a SHA-256 hash (%d bytes), got %d bytes","messagePattern":"(.+?)RuntimeExecutableHash must be a SHA-256 hash \\((.+?) bytes\\), got (.+?) bytes","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/internal/embeddedcli/embeddedcli.go","lineNumber":425,"sourceCode":"\t\thash := sha256.Sum256(content)\n\t\tmode := os.FileMode(header.Mode & 0777)\n\t\tif err := installVerifiedFile(path, bytes.NewReader(content), hash[:], mode, \"runtime asset\"); err != nil {\n\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","sourceCodeStart":407,"sourceCodeEnd":443,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/go/internal/embeddedcli/embeddedcli.go#L407-L443","documentation":"After confirming both members of a runtime pair are present, validateRuntimePairConfig checks that the wrapper executable's hash is exactly 32 bytes (SHA-256 size). A hash of any other length cannot be used by the verify-on-install pipeline, so Setup panics with the platform prefix (e.g. \"LinuxMuslRuntimeExecutableHash\") embedded in the message. This fail-fast check precedes any file writes.","triggerScenarios":"Calling Setup where cfg.LinuxMuslRuntimeExecutableHash (or the default RuntimeExecutableHash) is a hex string's bytes, an empty slice, or a non-SHA-256 digest while the corresponding executable and node are both set.","commonSituations":"Storing hashes as hex strings and forgetting hex.DecodeString; using a SHA-1 or truncated digest from an older pipeline; copy-pasting a hash across platforms with mismatched length.","solutions":["Decode the hex digest to 32 raw bytes with hex.DecodeString before assigning it to the hash field.","Recompute it directly: h := sha256.Sum256(wrapperBytes); cfg.LinuxMuslRuntimeExecutableHash = h[:].","Verify the digest source produces raw SHA-256 (32 bytes), not base64/hex text or a different algorithm's output."],"exampleFix":"// before\ncfg.LinuxMuslRuntimeExecutableHash = []byte(hashHex) // 64 bytes\n\n// after\nraw, err := hex.DecodeString(hashHex)\nif err != nil || len(raw) != sha256.Size { /* fix pipeline */ }\ncfg.LinuxMuslRuntimeExecutableHash = raw","handlingStrategy":"validation","validationCode":"func validWrapperHash(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, \"RuntimeExecutableHash must be a SHA-256 hash\") {\n            log.Fatalf(\"bad runtime executable hash: %s\", s)\n        }\n        panic(r)\n    }\n}()","preventionTips":["Always hex.DecodeString digest strings before assigning to hash fields.","Assert digest length right after generation in the build pipeline.","Keep a shared helper that produces ([32]byte, error) digests so the type enforces the length."],"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"}