router-for-me/CLIProxyAPI · error

failed to parse response JSON: %w

Error message

failed to parse response JSON: %w

What it means

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.

Source

Thrown at cmd/fetch_codex_models/main.go:302

func codexModelsURL(clientVersion string) (string, error) {
	u, err := url.Parse(codexModelsBaseURL + codexModelsPath)
	if err != nil {
		return "", err
	}
	if strings.TrimSpace(clientVersion) != "" {
		q := u.Query()
		q.Set("client_version", strings.TrimSpace(clientVersion))
		u.RawQuery = q.Encode()
	}
	return u.String(), nil
}

func countModels(raw []byte) (int, error) {
	var payload struct {
		Models []json.RawMessage `json:"models"`
	}
	if err := json.Unmarshal(raw, &payload); err != nil {
		return 0, fmt.Errorf("failed to parse response JSON: %w", err)
	}
	// Keep this check intentionally loose: fetch_codex_models dumps the upstream
	// Codex API payload. Strict CPA catalog validation belongs in
	// cmd/validate_codex_models and registry.ValidateCodexClientModelsJSON.
	if payload.Models == nil {
		return 0, fmt.Errorf("response JSON does not contain models array")
	}
	return len(payload.Models), nil
}

func prettyJSON(raw []byte) ([]byte, error) {
	var buf bytes.Buffer
	if err := json.Indent(&buf, raw, "", "  "); err != nil {
		return nil, err
	}
	buf.WriteByte('\n')
	return buf.Bytes(), nil
}

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Capture the raw body (curl the same models URL with the same token) and inspect what was actually returned.
  2. Bypass or configure the intercepting proxy; ensure no HTML block page is served for chatgpt.com backend endpoints.
  3. Retry once — truncated bodies from connection cuts are transient.
  4. If the shape genuinely changed upstream, update cmd/fetch_codex_models parsing and check CLIProxyAPI updates.
Defensive patterns

Strategy: type-guard

Validate before calling

// Pre-validate that the fetched body is JSON before counting
func isJSONBody(b []byte) bool {
    var v any
    return json.Unmarshal(b, &v) == nil
}

Type guard

func isJSONParseFailure(err error) bool {
    return err != nil && strings.Contains(err.Error(), "failed to parse response JSON")
}

Try / catch

if isJSONParseFailure(err) {
    // inspect/save the raw body; likely an HTML block page from an intercepting proxy
    logBodyForDiagnosis(raw)
}

Prevention

When it happens

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

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

Understand the failure class

Related errors


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/4d76f8d0cb96db86. Report an issue: GitHub.