{"record":{"id":"11afe769c2dbb0c2","repo":"github/copilot-sdk","slug":"s-must-be-a-sha-256-hash-d-bytes-got-d-bytes","errorCode":null,"errorMessage":"%s must be a SHA-256 hash (%d bytes), got %d bytes","messagePattern":"(.+?) must be a SHA-256 hash \\((.+?) bytes\\), got (.+?) bytes","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/internal/embeddedcli/embeddedcli.go","lineNumber":359,"sourceCode":"\t\treturn \"\", fmt.Errorf(\"creating install directory: %w\", err)\n\t}\n\n\tif release, _ := flock.Acquire(filepath.Join(installDir, \".copilot-cli.lock\")); release != nil {\n\t\tdefer release()\n\t}\n\tpath, err := installRuntimePair(installDir)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif err := installRuntimeAssets(installDir); err != nil {\n\t\treturn \"\", err\n\t}\n\treturn path, nil\n}\n\nfunc validateOptionalHash(reader io.Reader, hash []byte, name string) {\n\tif reader != nil && len(hash) != sha256.Size {\n\t\tpanic(fmt.Sprintf(\"%s must be a SHA-256 hash (%d bytes), got %d bytes\", name, sha256.Size, len(hash)))\n\t}\n}\n\nfunc installRuntimeAssets(installDir string) error {\n\tif config.RuntimeAssets == nil || runtimeAssetsInstalled {\n\t\treturn nil\n\t}\n\tarchiveBytes, err := io.ReadAll(config.RuntimeAssets)\n\tif closer, ok := config.RuntimeAssets.(io.Closer); ok {\n\t\tcloser.Close()\n\t}\n\tif err != nil {\n\t\treturn fmt.Errorf(\"reading runtime assets: %w\", err)\n\t}\n\tactual := sha256.Sum256(archiveBytes)\n\tif !bytes.Equal(actual[:], config.RuntimeAssetsHash) {\n\t\treturn fmt.Errorf(\"runtime assets hash mismatch\")\n\t}","sourceCodeStart":341,"sourceCodeEnd":377,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/go/internal/embeddedcli/embeddedcli.go#L341-L377","documentation":"validateOptionalHash enforces that when an optional embedded asset reader (e.g. RuntimeAssets, LinuxMuslRuntimeAssets) is provided, its companion hash must be exactly a SHA-256 digest (32 bytes). If a non-nil reader is paired with a hash of any other length, Setup panics so misconfigured integrity data is caught at startup rather than at install time. This protects the verify-on-write pipeline that compares written bytes against the digest.","triggerScenarios":"Calling Setup with cfg.RuntimeAssets non-nil but cfg.RuntimeAssetsHash set to a hex string's bytes, a truncated/short digest, an empty slice, or a SHA-1/MD5 digest instead of the raw 32-byte SHA-256.","commonSituations":"Passing a hex-encoded hash string (64 chars → 64 bytes) instead of the decoded 32 bytes; copying a hash field from a different asset; build tooling emitting the wrong digest length.","solutions":["Decode the hex hash to raw bytes before Setup: b, _ := hex.DecodeString(hashHex) and pass the 32-byte slice.","Recompute the digest: h := sha256.Sum256(assetBytes); use h[:].","If no hash is available, pass nil for the reader rather than a reader with a bogus hash."],"exampleFix":"// before\ncfg.RuntimeAssetsHash = []byte(\"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\") // 64 bytes\n\n// after\nraw, _ := hex.DecodeString(\"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\")\ncfg.RuntimeAssetsHash = raw // 32 bytes","handlingStrategy":"validation","validationCode":"func validOptionalHash(reader io.Reader, hash []byte) bool {\n    return reader == nil || len(hash) == sha256.Size\n}","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, \"must be a SHA-256 hash\") {\n            log.Fatalf(\"embedded asset hash misconfigured: %s\", s)\n        }\n        panic(r)\n    }\n}()","preventionTips":["Store hashes as [32]byte or []byte of raw digest, never hex/base64 strings.","Add a build-time/unit test asserting len(hash) == sha256.Size for every embedded asset.","hex-decode at the point the digest is produced by CI, not at Setup time."],"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"}