{"record":{"id":"ddd07b1defb4f21b","repo":"hashicorp/terraform","slug":"failed-to-encode-version-index-s","errorCode":null,"errorMessage":"failed to encode version index: %s","messagePattern":"failed to encode version index: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"internal/command/providers_mirror.go","lineNumber":344,"sourceCode":"\t\t// we're supporting network mirrors, to avoid having them briefly\n\t\t// become corrupted during updates.\n\t\terr = ioutil.WriteFile(filepath.Join(indexDir, \"index.json\"), mainIndexJSON, 0644)\n\t\tif err != nil {\n\t\t\tdiags = diags.Append(tfdiags.Sourceless(\n\t\t\t\ttfdiags.Error,\n\t\t\t\t\"Failed to update indexes\",\n\t\t\t\tfmt.Sprintf(\"Failed to write an updated JSON index for %s: %s.\", provider, err),\n\t\t\t))\n\t\t}\n\t\tfor version, archiveIndex := range indexArchives {\n\t\t\tversionIndex := map[string]interface{}{\n\t\t\t\t\"archives\": archiveIndex,\n\t\t\t}\n\t\t\tversionIndexJSON, err := json.MarshalIndent(versionIndex, \"\", \"  \")\n\t\t\tif err != nil {\n\t\t\t\t// Should never happen because the input here is entirely under\n\t\t\t\t// our control.\n\t\t\t\tpanic(fmt.Sprintf(\"failed to encode version index: %s\", err))\n\t\t\t}\n\t\t\terr = ioutil.WriteFile(filepath.Join(indexDir, version.String()+\".json\"), versionIndexJSON, 0644)\n\t\t\tif err != nil {\n\t\t\t\tdiags = diags.Append(tfdiags.Sourceless(\n\t\t\t\t\ttfdiags.Error,\n\t\t\t\t\t\"Failed to update indexes\",\n\t\t\t\t\tfmt.Sprintf(\"Failed to write an updated JSON index for %s v%s: %s.\", provider, version, err),\n\t\t\t\t))\n\t\t\t}\n\t\t}\n\t}\n\n\tc.showDiagnostics(diags)\n\tif diags.HasErrors() {\n\t\treturn 1\n\t}\n\treturn 0\n}","sourceCodeStart":326,"sourceCodeEnd":362,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/command/providers_mirror.go#L326-L362","documentation":"This panic fires when json.MarshalIndent fails to encode a per-version '<version>.json' index in providers_mirror.go:344. Like error 1000, the versionIndex map is internally constructed, so the failure indicates a programming regression that inserted an unmarshallable value type into archiveIndex.","triggerScenarios":"Invoked during `terraform providers mirror` for each provider version, when serializing the 'archives' sub-map. Fires only if an archiveIndex entry contains a type encoding/json cannot serialize (func, chan, recursive struct, unsupported map key).","commonSituations":"A refactor changes the archiveIndex value shape (e.g. adds a url.URL struct or a hash.Hash instead of the plain string/array) and the mirror command panics on the first version it processes.","solutions":["Diff providers_mirror.go around the indexArchives[version][platform] assignment — confirm values stay as the documented {url string, hashes []string} shape.","Add a focused unit test that builds indexArchives for one version/platform and asserts json.MarshalIndent succeeds.","Convert any new field to its string/[]string JSON form before inserting into archiveIndex."],"exampleFix":"// before\nindexArchives[version][platform.String()] = map[string]interface{}{\n  \"url\":   archiveURL,        // url.URL struct — not JSON-friendly\n  \"hashes\": []string{hash.String()},\n}\n// after\nindexArchives[version][platform.String()] = map[string]interface{}{\n  \"url\":   archiveURL.String(), // plain string\n  \"hashes\": []string{hash.String()},\n}","handlingStrategy":"validation","validationCode":"// Probe-serialize each archiveIndex before the real MarshalIndent.\nfor ver, idx := range indexArchives {\n  if _, err := json.Marshal(idx); err != nil {\n    return fmt.Errorf(\"archive index for %s not serializable: %w\", ver, err)\n  }\n}","typeGuard":"// n/a — map[string]map[string]interface{}; guard via marshalling probe","tryCatchPattern":null,"preventionTips":["Constrain archiveIndex values to {url string, hashes []string}.","Unit-test the marshal path for one version/platform in providers_mirror_test.go.","Codify the index shape in a typed struct (e.g. type archiveEntry struct{ URL string; Hashes []string }) so the compiler enforces JSON-friendliness."],"tags":["terraform-cli","json-marshal","panic","providers-mirror","invariant"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}