{"record":{"id":"2bc601a9341eff19","repo":"zeroclaw-labs/zeroclaw","slug":"notion-update-page-failed-status-truncated","errorCode":null,"errorMessage":"Notion update_page failed ({status}): {truncated}","messagePattern":"Notion update_page failed \\((.+?)\\): (.+?)","errorType":"http","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-tools/src/notion_tool.rs","lineNumber":152,"sourceCode":"        page_id: &str,\n        properties: &serde_json::Value,\n    ) -> anyhow::Result<serde_json::Value> {\n        let url = format!(\"{NOTION_API_BASE}/pages/{page_id}\");\n        let body = json!({ \"properties\": properties });\n        let resp = self\n            .http\n            .patch(&url)\n            .headers(self.headers()?)\n            .json(&body)\n            .timeout(std::time::Duration::from_secs(NOTION_REQUEST_TIMEOUT_SECS))\n            .send()\n            .await?;\n        let status = resp.status();\n        if !status.is_success() {\n            let text = resp.text().await.unwrap_or_default();\n            let truncated =\n                crate::util_helpers::truncate_with_ellipsis(&text, MAX_ERROR_BODY_CHARS);\n            anyhow::bail!(\"Notion update_page failed ({status}): {truncated}\");\n        }\n        resp.json().await.map_err(Into::into)\n    }\n\n    /// Search the Notion workspace by query string.\n    async fn search(&self, query: &str) -> anyhow::Result<serde_json::Value> {\n        let url = format!(\"{NOTION_API_BASE}/search\");\n        let body = json!({ \"query\": query });\n        let resp = self\n            .http\n            .post(&url)\n            .headers(self.headers()?)\n            .json(&body)\n            .timeout(std::time::Duration::from_secs(NOTION_REQUEST_TIMEOUT_SECS))\n            .send()\n            .await?;\n        let status = resp.status();\n        if !status.is_success() {","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-tools/src/notion_tool.rs#L134-L170","documentation":"The Notion tool's update_page action sent PATCH https://api.notion.com/v1/pages/{page_id} and got a non-2xx response. The wrapped status and body excerpt identify the rejection cause, almost always a property payload that does not match the page's database schema or an archived page.","triggerScenarios":"Sending a value with the wrong property type (e.g. rich_text for a select or number property), referencing a property that no longer exists, updating an archived/trashed page (400), page not shared with the integration (404), or invalid token (401).","commonSituations":"Sync jobs that push field updates into Notion break after schema drift: someone retyped a field from text to select, so the old payload shape now fails. Archived pages still referenced by stored ids are another frequent source.","solutions":["Match the body excerpt to the failing property name and fix its value type (select needs {select:{name}}, numbers need {number:n})","If the page was archived, restore it in Notion or drop it from the update queue","Re-read the page to refresh property names/types before building the update payload","For 404, fix sharing; for 401, rotate the token"],"exampleFix":"// before ('Status' is a select property)\n{\"action\":\"update_page\",\"page_id\":\"<id>\",\"properties\":{\"Status\":{\"rich_text\":[{\"text\":{\"content\":\"Done\"}}]}}}\n// after\n{\"action\":\"update_page\",\"page_id\":\"<id>\",\"properties\":{\"Status\":{\"select\":{\"name\":\"Done\"}}}}","handlingStrategy":"validation","validationCode":"// Before updating, confirm the page is live and capture property types\nlet page = notion.execute(json!({\"action\":\"read_page\",\"page_id\":id})).await?;\nif page.get(\"archived\") == Some(&json!(true)) { /* skip */ }","typeGuard":"fn is_editable_page(v: &serde_json::Value) -> bool {\n    v.get(\"archived\").and_then(|a| a.as_bool()) == Some(false)\n}","tryCatchPattern":"Err(e) if e.to_string().starts_with(\"Notion update_page failed (400)\") => {\n    // parse body excerpt for property name, re-read schema, coerce type, retry once\n}","preventionTips":["Map each outgoing field through the property type read from the page","Drop archived pages from update queues when Notion signals deletion","Keep payloads minimal: send only properties that actually changed"],"tags":["notion","http","api","page","update","rust"],"backgroundTag":"notion-api-error","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}