{"record":{"id":"d2eaa24dcc60e138","repo":"gastownhall/beads","slug":"notion-api-error-s-d-s","errorCode":null,"errorMessage":"Notion API error %s (%d): %s","messagePattern":"Notion API error (.+?) \\((.+?)\\): (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/notion/client.go","lineNumber":299,"sourceCode":"\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"request failed: %w\", err)\n\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":281,"sourceCodeEnd":303,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/notion/client.go#L281-L303","documentation":"Notion returned a non-2xx status and its JSON error body carried a structured message, so the library surfaces it as 'Notion API error <code> (<status>): <message>'. This is the server rejecting the request: bad token, missing permissions, invalid payload, rate limiting, etc. apiErr.Code is Notion's machine-readable error code (e.g. unauthorized, object_not_found, rate_limited).","triggerScenarios":"401 unauthorized (invalid/revoked integration token); 404 object_not_found (page/database ID wrong or not shared with the integration); 400 validation_error (malformed properties/filter); 429 rate_limited (too many requests); 403 restricted_resource.","commonSituations":"Token rotated/revoked in Notion; database created but never shared with the integration (Notion's connection menu); wrong database ID (missing/extra dashes is fine, but wrong ID 404s); burst-bulk syncs hitting rate limits.","solutions":["Match on the code: 'unauthorized' → regenerate the integration token; 'object_not_found' → share the target page/database with the integration.","For 'rate_limited' (429), retry with exponential backoff respecting the Retry-After header.","For 'validation_error', compare your request payload against the Notion API docs for that endpoint.","Confirm the database ID and that your integration has at least read access to it in Notion's UI."],"exampleFix":"// before\nresp, err := client.Query(ctx, q) // Notion API error unauthorized (401): API token is invalid.\n\n// after\nvar apiErr *notion.APIError\nif errors.As(err, &apiErr) && apiErr.Code == \"rate_limited\" {\n    time.Sleep(retryAfter)\n    resp, err = client.Query(ctx, q) // retry with backoff\n}","handlingStrategy":"try-catch","validationCode":"// pre-flight check\nreq, _ := http.NewRequestWithContext(ctx, http.MethodGet, \"https://api.notion.com/v1/users/me\", nil)\nreq.Header.Set(\"Authorization\", \"Bearer \"+token)\nreq.Header.Set(\"Notion-Version\", \"2022-06-28\")\nresp, err := http.DefaultClient.Do(req)\nif err == nil && resp.StatusCode == 401 {\n    return fmt.Errorf(\"notion token invalid\")\n}","typeGuard":null,"tryCatchPattern":"var apiErr *notion.APIError\nif errors.As(err, &apiErr) {\n    switch apiErr.Code {\n    case \"unauthorized\":  // fix token\n    case \"object_not_found\": // share DB with integration\n    case \"rate_limited\":  // backoff and retry\n    case \"validation_error\": // fix payload\n    }\n}","preventionTips":["Share every target database/page with the integration in Notion's UI.","Rotate tokens via secrets management, not manual edits.","Respect Retry-After and back off on 429s in bulk operations.","Validate payloads against the endpoint's documented schema before sending."],"tags":["notion","api-error","http-status","authentication"],"backgroundTag":"upstream-api-error","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}