anomalyco/sst · error
failed to parse API response: %v
Error message
failed to parse API response: %v
What it means
This error is returned by createOrUpdateRecord when the JSON body of the Cloudflare DNS-record API response cannot be unmarshaled into the expected CloudflareResponse struct. The library assumes the endpoint returns well-formed JSON matching its schema, so a non-JSON or structurally different body is treated as an unparseable response rather than an API error.
Source
Thrown at pkg/server/resource/cloudflare-dns-record.go:152
// Define response structures based on Cloudflare API docs
type CloudflareError struct {
Code int `json:"code"`
Message string `json:"message"`
}
type CloudflareResponse struct {
Success bool `json:"success"`
Errors []CloudflareError `json:"errors"`
Messages []string `json:"messages"`
Result struct {
Id string `json:"id"`
} `json:"result"`
}
var apiResponse CloudflareResponse
if err := json.Unmarshal(body, &apiResponse); err != nil {
return "", fmt.Errorf("failed to parse API response: %v", err)
}
// Check if the response was successful
if resp.StatusCode < 200 || resp.StatusCode >= 300 || !apiResponse.Success {
// Check for "already exists" in error messages
if len(apiResponse.Errors) > 0 {
for _, cfError := range apiResponse.Errors {
// Check if message contains "already exists" regardless of error code
if strings.Contains(strings.ToLower(cfError.Message), "already exists") {
return "existing-record", nil
}
}
}
// If not an "already exists" error, return the error information
errorMsgs := []string{}
for _, cfError := range apiResponse.Errors {
errorMsgs = append(errorMsgs, fmt.Sprintf("%s", cfError.Message))View on GitHub (pinned to a0bd20f762)
Solutions
- Print/log the raw response body and status code to see what was actually returned
- Verify the API token is valid and scoped to the zone: curl -H "Authorization: Bearer $TOKEN" https://api.cloudflare.com/client/v4/user/tokens/verify
- Retry later if it's an HTML challenge/rate-limit page; reduce request frequency
- Check for a proxy/firewall intercepting traffic to api.cloudflare.com
- If the API response shape changed, update the CloudflareResponse struct to match
Example fix
// before
var apiResponse CloudflareResponse
if err := json.Unmarshal(body, &apiResponse); err != nil {
return "", fmt.Errorf("failed to parse API response: %v", err)
}
// after — include body/status for diagnosis
var apiResponse CloudflareResponse
if err := json.Unmarshal(body, &apiResponse); err != nil {
return "", fmt.Errorf("failed to parse API response (status %d): %v: body: %s", resp.StatusCode, err, string(body))
} Defensive patterns
Strategy: try-catch
Validate before calling
// pre-flight: verify the token before creating records tokenOK := verifyCloudflareToken(apiToken) // calls /user/tokens/verify and checks JSON success==true
Try / catch
id, err := record.Create(input, &out)
if err != nil {
if strings.Contains(err.Error(), "failed to parse API response") {
// non-JSON body: log status/body, back off, retry
return fmt.Errorf("cloudflare returned a non-JSON response; check token/proxy and retry: %w", err)
}
return err
} Prevention
- Validate the Cloudflare API token with /user/tokens/verify before deploying
- Avoid deploying behind corporate proxies that inject HTML error pages
- Add retry with backoff for 4xx/5xx responses before parsing the body
- Log the raw response body on parse failure for diagnosis
When it happens
Trigger: The POST to the Cloudflare DNS record endpoint returns a body that is not the expected JSON envelope — e.g. an HTML error page from a proxy/firewall, a truncated or empty body, an HTML Cloudflare challenge/rate-limit page (status 503/1015), or JSON whose types don't fit the struct (e.g. result as a string or errors entries as strings).
Common situations: Invalid or expired API token causing an HTML login redirect; corporate proxy or Cloudflare WAF returning an HTML block page; network middleware returning plain text; Cloudflare API version change altering the response shape; request hitting an interposed captive portal.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Could not find hosted zone for domain ${inputs.domain}
- failed to decode cloudflare unenv config: %w %s
- Cloudflare API error: %s
- failed to create DNS record, status: %d, response: %s
- failed to marshal metadata: %w
AI-assisted analysis of anomalyco/sst@a0bd20f762 (2026-08-30).
Data as JSON: /api/errors/ae79c89080bb4733.
Report an issue: GitHub.