{"record":{"id":"ee41f5f0ed036c2e","repo":"zeroclaw-labs/zeroclaw","slug":"qdrant-scroll-failed-status-text","errorCode":null,"errorMessage":"Qdrant scroll failed ({status}): {text}","messagePattern":"Qdrant scroll failed \\((.+?)\\): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-config/src/schema/v2.rs","lineNumber":3219,"sourceCode":"        if let Some(ref offset) = next_offset {\n            scroll_body[\"offset\"] = offset.clone();\n        }\n\n        let url = format!(\"{base_url}/collections/{collection}/points/scroll\");\n        let mut req = client.request(reqwest::Method::POST, &url);\n        if let Some(key) = api_key {\n            req = req.header(\"api-key\", key);\n        }\n        let resp = req\n            .header(\"Content-Type\", \"application/json\")\n            .json(&scroll_body)\n            .send()\n            .await\n            .context(\"[system] Qdrant V3 migration: scroll request failed\")?;\n        if !resp.status().is_success() {\n            let status = resp.status();\n            let text = resp.text().await.unwrap_or_default();\n            anyhow::bail!(\"Qdrant scroll failed ({status}): {text}\");\n        }\n\n        #[derive(serde::Deserialize)]\n        struct ScrollPage {\n            result: ScrollResult,\n        }\n        #[derive(serde::Deserialize)]\n        struct ScrollResult {\n            points: Vec<ScrollPoint>,\n            #[serde(default)]\n            next_page_offset: Option<serde_json::Value>,\n        }\n        #[derive(serde::Deserialize)]\n        struct ScrollPoint {\n            id: serde_json::Value,\n        }\n\n        let page: ScrollPage = resp","sourceCodeStart":3201,"sourceCodeEnd":3237,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-config/src/schema/v2.rs#L3201-L3237","documentation":"Inside migrate_qdrant_collection_to_v3, ZeroClaw POSTs to {base_url}/collections/{collection}/points/scroll with a filter for points whose agent_id payload is empty (the pre-v3 shape) to backfill them with agent_id = \"default\". This error fires when Qdrant answers the scroll with any non-2xx status; the message embeds the HTTP status code and Qdrant's response body. Common statuses: 404 (collection does not exist), 401/403 (missing/wrong api-key header), 400 (rejected filter or payload index issues).","triggerScenarios":"Running the V3 migration against a base_url/collection name that does not exist in Qdrant (404); Qdrant requires an API key but api_key was None or wrong (401); the collection was created with incompatible settings so the is_empty filter is rejected (400); Qdrant cloud URL wrong or pointing at the dashboard port instead of the REST port (6333).","commonSituations":"Upgrading ZeroClaw to V3 memory schema while the configured Qdrant collection was renamed or never created; local Qdrant not started yet when migration runs; API key rotated in Qdrant but not in ZeroClaw config; typo in qdrant base_url or collection name.","solutions":["Read the embedded status: 404 → verify the collection name and create it (or let ZeroClaw create it) before migrating","401/403 → supply/correct the Qdrant api_key so the 'api-key' header is accepted","Confirm Qdrant is reachable: curl {base_url}/collections and check the target collection appears","Fix base_url (scheme + host + REST port, usually 6333, no trailing slash needed) and retry the migration — it is idempotent because it only touches points lacking agent_id"],"exampleFix":"# before\n[qdrant]\nurl = \"http://localhost:7333\"   # wrong port\ncollection = \"memories_v2\"\n\n# after\n[qdrant]\nurl = \"http://localhost:6333\"\ncollection = \"zeroclaw_memories\"","handlingStrategy":"validation","validationCode":"// preflight before migrate_qdrant_collection_to_v3:\nasync fn qdrant_collection_reachable(client: &reqwest::Client, base: &str, coll: &str, key: Option<&str>) -> Result<bool> {\n    let mut r = client.get(format!(\"{}/collections/{}\", base.trim_end_matches('/'), coll));\n    if let Some(k) = key { r = r.header(\"api-key\", k); }\n    Ok(r.send().await?.status().is_success())\n}","typeGuard":null,"tryCatchPattern":"if let Err(e) = migrate_qdrant_collection_to_v3(&client, &url, &coll, key).await {\n    let msg = e.to_string();\n    if msg.starts_with(\"Qdrant scroll failed\") {\n        eprintln!(\"migration preflight failed — check collection name, api key, and that Qdrant is up: {msg}\");\n    }\n    return Err(e);\n}","preventionTips":["Run a GET /collections/{name} health check before starting migrations","Pin base_url to the REST port (6333) and store the api key next to it in config","Start local Qdrant before the app in docker-compose (depends_on + healthcheck)"],"tags":["qdrant","migration","vector-db","http","database"],"backgroundTag":"qdrant-api-error","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}