{"record":{"id":"a1f583893e06d76f","repo":"chenhg5/cc-connect","slug":"parse-json-from-s-w","errorCode":null,"errorMessage":"parse JSON from %s: %w","messagePattern":"parse JSON from (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/provider_presets.go","lineNumber":155,"sourceCode":"\tclient := &http.Client{Timeout: timeout}\n\tresp, err := client.Get(url)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"HTTP GET %s: %w\", url, err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"HTTP GET %s: status %d\", url, resp.StatusCode)\n\t}\n\n\tbody, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"read body from %s: %w\", url, err)\n\t}\n\n\tvar result ProviderPresetsResponse\n\tif err := json.Unmarshal(body, &result); err != nil {\n\t\treturn nil, fmt.Errorf(\"parse JSON from %s: %w\", url, err)\n\t}\n\treturn &result, nil\n}\n","sourceCodeStart":137,"sourceCodeEnd":159,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/provider_presets.go#L137-L159","documentation":"The fetched presets body is not valid JSON for the expected `ProviderPresetsResponse` shape; `json.Unmarshal` failed and the error is wrapped as `parse JSON from <url>: <cause>`. The HTTP layer succeeded but the payload is malformed or structurally incompatible.","triggerScenarios":"Calling fetchPresetsFromURL against a URL that returns HTML (error page, login page), an empty body, truncated JSON (e.g. cut off by the 1 MiB LimitReader), or JSON whose fields do not match ProviderPresetsResponse types.","commonSituations":"URL accidentally points to an HTML page instead of raw JSON; server behind an auth wall returns a login redirect body with 200; presets schema changed upstream while the client expects the old shape; response larger than the 1 MiB cap so the JSON is truncated.","solutions":["curl the URL and validate the body is well-formed JSON (`jq . <response.json>`).","Point the presets source at the correct raw JSON URL (for GitHub use raw.githubusercontent.com, not the HTML page).","Check whether the response exceeds 1 MiB and, if so, raise the LimitReader cap or host a smaller file.","Confirm the upstream JSON still matches the ProviderPresetsResponse field names/types; update either side if the schema drifted."],"exampleFix":"// before\nvar result ProviderPresetsResponse\nif err := json.Unmarshal(body, &result); err != nil {\n    return nil, fmt.Errorf(\"parse JSON from %s: %w\", url, err)\n}\n\n// after (surface context about the offending body)\nvar result ProviderPresetsResponse\nif err := json.Unmarshal(body, &result); err != nil {\n    return nil, fmt.Errorf(\"parse JSON from %s: %w (first 200 bytes: %q)\", url, err, body[:min(200, len(body))])\n}","handlingStrategy":"validation","validationCode":"trimmed := bytes.TrimSpace(body)\nif len(trimmed) == 0 || trimmed[0] != '{' { return fmt.Errorf(\"%s did not return JSON\", url) }\nif err := json.Valid(trimmed); err != nil { return fmt.Errorf(\"invalid JSON from %s: %w\", url, err) }","typeGuard":null,"tryCatchPattern":"var result ProviderPresetsResponse\nif err := json.Unmarshal(body, &result); err != nil {\n    slog.Warn(\"bad presets payload\", \"url\", url, \"error\", err)\n    return staleOrDefaultPresets(), nil\n}","preventionTips":["Point sources at raw JSON endpoints, never HTML pages.","Keep client and server presets schemas in sync (version the payload).","Log the first bytes of an unparseable body to diagnose HTML-vs-JSON quickly.","Remember the 1 MiB LimitReader cap when hosting large presets files."],"tags":["json","parsing","http","go"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}