{"record":{"id":"dd9bd41902bb695d","repo":"gastownhall/beads","slug":"notion-api-error-d-s","errorCode":null,"errorMessage":"Notion API error (%d): %s","messagePattern":"Notion API error \\((.+?)\\): (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/notion/client.go","lineNumber":301,"sourceCode":"\t}\n\tdefer func() { _ = resp.Body.Close() }()\n\n\tbody, err := io.ReadAll(io.LimitReader(resp.Body, maxResponseBytes))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"read response: %w\", err)\n\t}\n\tif resp.StatusCode >= 200 && resp.StatusCode < 300 {\n\t\treturn body, nil\n\t}\n\n\tvar apiErr struct {\n\t\tCode    string `json:\"code\"`\n\t\tMessage string `json:\"message\"`\n\t}\n\tif err := json.Unmarshal(body, &apiErr); err == nil && apiErr.Message != \"\" {\n\t\treturn nil, fmt.Errorf(\"Notion API error %s (%d): %s\", apiErr.Code, resp.StatusCode, apiErr.Message)\n\t}\n\treturn nil, fmt.Errorf(\"Notion API error (%d): %s\", resp.StatusCode, strings.TrimSpace(string(body)))\n}\n","sourceCodeStart":283,"sourceCodeEnd":303,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/notion/client.go#L283-L303","documentation":"Fallback error when Notion returns a non-2xx response whose body is NOT a parseable JSON error with a message (or json.Unmarshal fails). The raw (trimmed) body is included in the message. Indicates either an unexpected server-side response (HTML error page from a proxy, empty body) or a non-JSON gateway response.","triggerScenarios":"Notion outage returning HTML/plain-text error pages via a load balancer; a corporate proxy intercepting and returning its own error page; 502/504 from an intermediary; empty response body with an error status; Notion changing its error payload shape.","commonSituations":"Company firewall blocking api.notion.com and returning an HTML block page; WAF rejecting the request; transient Notion incidents (status.notion.so) returning non-JSON 5xx responses.","solutions":["Read the raw body in the message to see who actually produced the error (Notion vs. a proxy).","Check https://status.notion.so for an ongoing incident; retry with backoff if it's a 5xx.","Verify no proxy/WAF is intercepting api.notion.com (try from a different network or curl the endpoint).","If persistent and the body is an HTML block page, work with network admin to allow Notion API traffic."],"exampleFix":"// before\nif err != nil { return err } // Notion API error (502): <html>Bad Gateway</html>\n\n// after\nvar apiErr *notion.APIError\nif errors.As(err, &apiErr) && apiErr.StatusCode >= 500 {\n    return retryWithBackoff(ctx, op) // transient upstream error\n}\nreturn err","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"var apiErr *notion.APIError\nif errors.As(err, &apiErr) && apiErr.StatusCode >= 500 {\n    // transient/upstream: retry with backoff\n} else if strings.Contains(err.Error(), \"Notion API error (\") {\n    // non-JSON body: inspect raw message, likely proxy or outage\n}","preventionTips":["Check status.notion.so during incidents; add retries for 5xx.","Ensure no WAF/proxy intercepts api.notion.com in your environment.","Log the full error message (it contains the raw body) for diagnosis."],"tags":["notion","api-error","http-status","non-json-response"],"backgroundTag":"upstream-api-error","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}