{"record":{"id":"e52c2c3961046ce3","repo":"github/copilot-sdk","slug":"runtime-assets-hash-mismatch","errorCode":null,"errorMessage":"runtime assets hash mismatch","messagePattern":"runtime assets hash mismatch","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/internal/embeddedcli/embeddedcli.go","lineNumber":376,"sourceCode":"\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}\n\tgzipReader, err := gzip.NewReader(bytes.NewReader(archiveBytes))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"opening runtime assets: %w\", err)\n\t}\n\tdefer gzipReader.Close()\n\ttarReader := tar.NewReader(gzipReader)\n\tfor {\n\t\theader, err := tarReader.Next()\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t}\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"reading runtime assets: %w\", err)\n\t\t}\n\t\tif header.Typeflag != tar.TypeReg {\n\t\t\tcontinue\n\t\t}","sourceCodeStart":358,"sourceCodeEnd":394,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/go/internal/embeddedcli/embeddedcli.go#L358-L394","documentation":"installRuntimeAssets computes sha256 over the read archive bytes and compares with config.RuntimeAssetsHash. A mismatch aborts extraction. The library verifies integrity so corrupted or mismatched runtime assets are never written to disk.","triggerScenarios":"sha256(RuntimeAssets bytes) != config.RuntimeAssetsHash: the embedded archive was rebuilt without updating the hash, the download was corrupted, or a different archive version was supplied with a stale hash.","commonSituations":"Regenerating runtime assets in CI but forgetting to regenerate RuntimeAssetsHash; proxy/cache serving a stale archive; truncation during a partial download.","solutions":["Recompute the SHA-256 of the archive and update config.RuntimeAssetsHash","Re-download or re-embed the runtime archive and retry","Ensure asset and hash are produced together by the same build step","Check intermediary caches/proxies for stale artifacts"],"exampleFix":"// before\nRuntimeAssetsHash: []byte(oldHash) // mismatch after assets rebuilt\n// after\narchive, _ := os.ReadFile(\"runtime.tar.gz\")\nsum := sha256.Sum256(archive)\ncfg.RuntimeAssets = bytes.NewReader(archive)\ncfg.RuntimeAssetsHash = sum[:]","handlingStrategy":"validation","validationCode":"archive, err := io.ReadAll(src)\nif err != nil { return err }\nsum := sha256.Sum256(archive)\nif !bytes.Equal(sum[:], cfg.RuntimeAssetsHash) {\n    return fmt.Errorf(\"archive hash %x != expected %x; rebuild assets\", sum, cfg.RuntimeAssetsHash)\n}","typeGuard":null,"tryCatchPattern":"err := embeddedcli.InstallRuntime(ctx, cfg, dir)\nif err != nil && strings.Contains(err.Error(), \"runtime assets hash mismatch\") {\n    return fmt.Errorf(\"stale or corrupted runtime archive: re-download/re-embed and regenerate its hash\")\n}","preventionTips":["Generate archive and hash in the same CI step","Verify downloaded archive hashes before install","Bust caches/proxies when runtime assets change"],"tags":["checksum","integrity","archive"],"backgroundTag":"checksum-mismatch","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"}