{"record":{"id":"ae79c89080bb4733","repo":"anomalyco/sst","slug":"failed-to-parse-api-response-v","errorCode":null,"errorMessage":"failed to parse API response: %v","messagePattern":"failed to parse API response: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/server/resource/cloudflare-dns-record.go","lineNumber":152,"sourceCode":"\t\n\t// Define response structures based on Cloudflare API docs\n\ttype CloudflareError struct {\n\t\tCode    int    `json:\"code\"`\n\t\tMessage string `json:\"message\"`\n\t}\n\n\ttype CloudflareResponse struct {\n\t\tSuccess  bool              `json:\"success\"`\n\t\tErrors   []CloudflareError `json:\"errors\"`\n\t\tMessages []string          `json:\"messages\"`\n\t\tResult   struct {\n\t\t\tId string `json:\"id\"`\n\t\t} `json:\"result\"`\n\t}\n\n\tvar apiResponse CloudflareResponse\n\tif err := json.Unmarshal(body, &apiResponse); err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to parse API response: %v\", err)\n\t}\n\n\t// Check if the response was successful\n\tif resp.StatusCode < 200 || resp.StatusCode >= 300 || !apiResponse.Success {\n\t\t// Check for \"already exists\" in error messages\n\t\tif len(apiResponse.Errors) > 0 {\n\t\t\tfor _, cfError := range apiResponse.Errors {\n\t\t\t\t// Check if message contains \"already exists\" regardless of error code\n\t\t\t\tif strings.Contains(strings.ToLower(cfError.Message), \"already exists\") {\n\t\t\t\t\treturn \"existing-record\", nil\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t// If not an \"already exists\" error, return the error information\n\t\terrorMsgs := []string{}\n\t\tfor _, cfError := range apiResponse.Errors {\n\t\t\terrorMsgs = append(errorMsgs, fmt.Sprintf(\"%s\", cfError.Message))","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/anomalyco/sst/blob/a0bd20f762883e72a35caccb4896c42ce5b3f707/pkg/server/resource/cloudflare-dns-record.go#L134-L170","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"// before\nvar apiResponse CloudflareResponse\nif err := json.Unmarshal(body, &apiResponse); err != nil {\n    return \"\", fmt.Errorf(\"failed to parse API response: %v\", err)\n}\n// after — include body/status for diagnosis\nvar apiResponse CloudflareResponse\nif err := json.Unmarshal(body, &apiResponse); err != nil {\n    return \"\", fmt.Errorf(\"failed to parse API response (status %d): %v: body: %s\", resp.StatusCode, err, string(body))\n}","handlingStrategy":"try-catch","validationCode":"// pre-flight: verify the token before creating records\ntokenOK := verifyCloudflareToken(apiToken) // calls /user/tokens/verify and checks JSON success==true","typeGuard":null,"tryCatchPattern":"id, err := record.Create(input, &out)\nif err != nil {\n    if strings.Contains(err.Error(), \"failed to parse API response\") {\n        // non-JSON body: log status/body, back off, retry\n        return fmt.Errorf(\"cloudflare returned a non-JSON response; check token/proxy and retry: %w\", err)\n    }\n    return err\n}","preventionTips":["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"],"tags":["cloudflare","dns","json","http-response","parsing"],"backgroundTag":"api-response-parse-failed","analyzedSha":"a0bd20f762883e72a35caccb4896c42ce5b3f707","analyzedAt":"2026-08-30T11:26:00.383Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}