{"record":{"id":"e9e1066c8613196f","repo":"github/copilot-sdk","slug":"opening-runtime-assets-w","errorCode":null,"errorMessage":"opening runtime assets: %w","messagePattern":"opening runtime assets: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/internal/embeddedcli/embeddedcli.go","lineNumber":380,"sourceCode":"\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}\n\t\tclean := filepath.Clean(filepath.FromSlash(header.Name))\n\t\tif !filepath.IsLocal(clean) {\n\t\t\treturn fmt.Errorf(\"unsafe runtime asset path %q\", header.Name)\n\t\t}","sourceCodeStart":362,"sourceCodeEnd":398,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/go/internal/embeddedcli/embeddedcli.go#L362-L398","documentation":"After hash verification, installRuntimeAssets opens the archive bytes as a gzip stream with gzip.NewReader. Failure is wrapped as \"opening runtime assets\". This means the bytes are not valid gzip data.","triggerScenarios":"gzip.NewReader(bytes.NewReader(archiveBytes)) returns a header error: the asset is a plain tar (not .tar.gz), an HTML error page from a failed download, or a corrupt/truncated gzip file.","commonSituations":"CI artifact upload mislabeled or corrupted; a download URL returning an error page that was saved as the archive; packaging the wrong (uncompressed) file.","solutions":["Verify the archive is gzip (file runtime.tar.gz / gzip -t)","Re-download or re-embed the correct .tar.gz asset","Check the download source isn't returning HTML/error bodies (log first bytes on failure)","Confirm RuntimeAssetsHash was computed over the same gzip archive being supplied"],"exampleFix":"// before\nresp, _ := http.Get(url)\ncfg.RuntimeAssets = resp.Body // may be an error page\n// after\nif resp.StatusCode != http.StatusOK {\n    return fmt.Errorf(\"download failed: %s\", resp.Status)\n}\ncfg.RuntimeAssets = resp.Body","handlingStrategy":"validation","validationCode":"archive, _ := io.ReadAll(src)\nif len(archive) < 2 || archive[0] != 0x1f || archive[1] != 0x8b {\n    return fmt.Errorf(\"not a gzip archive (first bytes: %q)\", archive[:min(16, len(archive))])\n}","typeGuard":"func isGzip(b []byte) bool { return len(b) >= 2 && b[0] == 0x1f && b[1] == 0x8b }","tryCatchPattern":"err := embeddedcli.InstallRuntime(ctx, cfg, dir)\nif err != nil && strings.Contains(err.Error(), \"opening runtime assets\") {\n    return fmt.Errorf(\"runtime asset is not valid gzip: verify download source returned the archive, not an error page\")\n}","preventionTips":["Check HTTP status codes before treating a response body as the archive","Validate gzip magic bytes (0x1f 0x8b) before install","Package .tar.gz (not plain tar) when the hash pipeline expects gzip"],"tags":["gzip","archive","integrity"],"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-16T04:17:20.429Z"}