zeroclaw-labs/zeroclaw · error · anyhow::Error

Notion create_page failed ({status}): {truncated}

Error message

Notion create_page failed ({status}): {truncated}

What it means

The Notion tool's create_page action sent POST https://api.notion.com/v1/pages and Notion rejected it with a non-2xx status; the message includes the status and truncated response body explaining why the page could not be created.

Source

Thrown at crates/zeroclaw-tools/src/notion_tool.rs:126

        let url = format!("{NOTION_API_BASE}/pages");
        let mut body = json!({ "properties": properties });
        if let Some(db_id) = database_id {
            body["parent"] = json!({ "database_id": db_id });
        }
        let resp = self
            .http
            .post(&url)
            .headers(self.headers()?)
            .json(&body)
            .timeout(std::time::Duration::from_secs(NOTION_REQUEST_TIMEOUT_SECS))
            .send()
            .await?;
        let status = resp.status();
        if !status.is_success() {
            let text = resp.text().await.unwrap_or_default();
            let truncated =
                crate::util_helpers::truncate_with_ellipsis(&text, MAX_ERROR_BODY_CHARS);
            anyhow::bail!("Notion create_page failed ({status}): {truncated}");
        }
        resp.json().await.map_err(Into::into)
    }

    /// Update an existing Notion page's properties.
    async fn update_page(
        &self,
        page_id: &str,
        properties: &serde_json::Value,
    ) -> anyhow::Result<serde_json::Value> {
        let url = format!("{NOTION_API_BASE}/pages/{page_id}");
        let body = json!({ "properties": properties });
        let resp = self
            .http
            .patch(&url)
            .headers(self.headers()?)
            .json(&body)
            .timeout(std::time::Duration::from_secs(NOTION_REQUEST_TIMEOUT_SECS))

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Inspect the status and body excerpt: 400 validation_error usually names the offending property
  2. Read the parent database first and build the properties payload from its actual property names and types
  3. For 404, share the parent database/page with the integration before creating under it
  4. Confirm the title property is included and typed as title/rich_text as the schema requires
  5. For auth failures, rotate and reconfigure the integration token

Example fix

// before (property 'Priority' is a number in the database)
{"action":"create_page","parent":{"database_id":"<id>"},"properties":{"Priority":{"rich_text":[{"text":{"content":"high"}}]}}}
// after
{"action":"create_page","parent":{"database_id":"<id>"},"properties":{"Priority":{"number":1}}}
Defensive patterns

Strategy: validation

Validate before calling

// Build properties from the live schema: read the database, map each property
type, then emit
fn coerce_value(prop_type: &str, raw: &str) -> serde_json::Value {
    match prop_type {
        "number" => json!({"number": raw.parse::<f64>().unwrap_or(0.0) }),
        "select" => json!({"select": {"name": raw } }),
        _ => json!({"rich_text": [{"text": {"content": raw }}]}),
    }
}

Try / catch

Err(e) if e.to_string().contains("create_page failed (400)") => {
    // re-read parent schema, rebuild payload once, then fail loudly if still 400
}

Prevention

When it happens

Trigger: Parent database or page not shared with the integration (404); properties payload that does not match the parent database's schema, e.g. sending a title value for a property defined as a number (400 validation_error); missing required title property; invalid parent object; bad token (401/403).

Common situations: Automations that create rows from templates break when the database schema changes (a property renamed or retyped) while the payload was hardcoded. Also: creating a page under a parent page that the integration cannot see, and copy-pasted payloads from a different database.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/08934f2b0b5b8b58. Report an issue: GitHub.