{"record":{"id":"4d76f8d0cb96db86","repo":"router-for-me/CLIProxyAPI","slug":"failed-to-parse-response-json-w","errorCode":null,"errorMessage":"failed to parse response JSON: %w","messagePattern":"failed to parse response JSON: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/fetch_codex_models/main.go","lineNumber":302,"sourceCode":"func codexModelsURL(clientVersion string) (string, error) {\n\tu, err := url.Parse(codexModelsBaseURL + codexModelsPath)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif strings.TrimSpace(clientVersion) != \"\" {\n\t\tq := u.Query()\n\t\tq.Set(\"client_version\", strings.TrimSpace(clientVersion))\n\t\tu.RawQuery = q.Encode()\n\t}\n\treturn u.String(), nil\n}\n\nfunc countModels(raw []byte) (int, error) {\n\tvar payload struct {\n\t\tModels []json.RawMessage `json:\"models\"`\n\t}\n\tif err := json.Unmarshal(raw, &payload); err != nil {\n\t\treturn 0, fmt.Errorf(\"failed to parse response JSON: %w\", err)\n\t}\n\t// Keep this check intentionally loose: fetch_codex_models dumps the upstream\n\t// Codex API payload. Strict CPA catalog validation belongs in\n\t// cmd/validate_codex_models and registry.ValidateCodexClientModelsJSON.\n\tif payload.Models == nil {\n\t\treturn 0, fmt.Errorf(\"response JSON does not contain models array\")\n\t}\n\treturn len(payload.Models), nil\n}\n\nfunc prettyJSON(raw []byte) ([]byte, error) {\n\tvar buf bytes.Buffer\n\tif err := json.Indent(&buf, raw, \"\", \"  \"); err != nil {\n\t\treturn nil, err\n\t}\n\tbuf.WriteByte('\\n')\n\treturn buf.Bytes(), nil\n}","sourceCodeStart":284,"sourceCodeEnd":320,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/cmd/fetch_codex_models/main.go#L284-L320","documentation":"countModels in cmd/fetch_codex_models/main.go unmarshals the fetched models payload into `{Models []json.RawMessage}`. If the body is not valid JSON (or not a JSON object), json.Unmarshal fails and the error wraps as `failed to parse response JSON: %w`. This means the endpoint answered 2xx but the body is not the expected JSON document — typically an HTML error page, empty body, or a proxy interception.","triggerScenarios":"2xx response containing HTML (captive portal, corporate proxy block page, Cloudflare interstitial); empty or truncated body due to connection cut mid-transfer; wrong URL composition; response shape changed to a non-object JSON scalar.","commonSituations":"Running the fetch tool behind corporate proxies that inject HTML; CDN/WAF challenges; a truncated response from an unstable network; upstream A/B changes to the endpoint.","solutions":["Capture the raw body (curl the same models URL with the same token) and inspect what was actually returned.","Bypass or configure the intercepting proxy; ensure no HTML block page is served for chatgpt.com backend endpoints.","Retry once — truncated bodies from connection cuts are transient.","If the shape genuinely changed upstream, update cmd/fetch_codex_models parsing and check CLIProxyAPI updates."],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"// Pre-validate that the fetched body is JSON before counting\nfunc isJSONBody(b []byte) bool {\n    var v any\n    return json.Unmarshal(b, &v) == nil\n}","typeGuard":"func isJSONParseFailure(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"failed to parse response JSON\")\n}","tryCatchPattern":"if isJSONParseFailure(err) {\n    // inspect/save the raw body; likely an HTML block page from an intercepting proxy\n    logBodyForDiagnosis(raw)\n}","preventionTips":["Sanity-check that the response body starts with '{' before parsing.","Exclude Codex endpoints from corporate proxy interception.","Retry once on truncated bodies caused by connection cuts."],"tags":["codex","json","parsing","proxy"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}