chenhg5/cc-connect · error

parse JSON from %s: %w

Error message

parse JSON from %s: %w

What it means

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.

Source

Thrown at core/provider_presets.go:155

	client := &http.Client{Timeout: timeout}
	resp, err := client.Get(url)
	if err != nil {
		return nil, fmt.Errorf("HTTP GET %s: %w", url, err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("HTTP GET %s: status %d", url, resp.StatusCode)
	}

	body, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
	if err != nil {
		return nil, fmt.Errorf("read body from %s: %w", url, err)
	}

	var result ProviderPresetsResponse
	if err := json.Unmarshal(body, &result); err != nil {
		return nil, fmt.Errorf("parse JSON from %s: %w", url, err)
	}
	return &result, nil
}

View on GitHub (pinned to 4000b2338a)

Solutions

  1. curl the URL and validate the body is well-formed JSON (`jq . <response.json>`).
  2. Point the presets source at the correct raw JSON URL (for GitHub use raw.githubusercontent.com, not the HTML page).
  3. Check whether the response exceeds 1 MiB and, if so, raise the LimitReader cap or host a smaller file.
  4. Confirm the upstream JSON still matches the ProviderPresetsResponse field names/types; update either side if the schema drifted.

Example fix

// before
var result ProviderPresetsResponse
if err := json.Unmarshal(body, &result); err != nil {
    return nil, fmt.Errorf("parse JSON from %s: %w", url, err)
}

// after (surface context about the offending body)
var result ProviderPresetsResponse
if err := json.Unmarshal(body, &result); err != nil {
    return nil, fmt.Errorf("parse JSON from %s: %w (first 200 bytes: %q)", url, err, body[:min(200, len(body))])
}
Defensive patterns

Strategy: validation

Validate before calling

trimmed := bytes.TrimSpace(body)
if len(trimmed) == 0 || trimmed[0] != '{' { return fmt.Errorf("%s did not return JSON", url) }
if err := json.Valid(trimmed); err != nil { return fmt.Errorf("invalid JSON from %s: %w", url, err) }

Try / catch

var result ProviderPresetsResponse
if err := json.Unmarshal(body, &result); err != nil {
    slog.Warn("bad presets payload", "url", url, "error", err)
    return staleOrDefaultPresets(), nil
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/a1f583893e06d76f. Report an issue: GitHub.