{"record":{"id":"866dafa61455e639","repo":"zeroclaw-labs/zeroclaw","slug":"qdrant-set-payload-failed-status-text","errorCode":null,"errorMessage":"Qdrant set payload failed ({status}): {text}","messagePattern":"Qdrant set payload failed \\((.+?)\\): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-config/src/schema/v2.rs","lineNumber":3262,"sourceCode":"            let body = serde_json::json!({\n                \"payload\": { \"agent_id\": QDRANT_DEFAULT_AGENT_ID },\n                \"points\": ids,\n            });\n            let mut req = client.request(reqwest::Method::POST, &set_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                .query(&[(\"wait\", \"true\")])\n                .json(&body)\n                .send()\n                .await\n                .context(\"[system] Qdrant V3 migration: set payload 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 set payload failed ({status}): {text}\");\n            }\n            let batch_count = body[\"points\"].as_array().map(|a| a.len()).unwrap_or(0);\n            updated += batch_count;\n        }\n\n        match page.result.next_page_offset {\n            Some(offset) if !offset.is_null() => next_offset = Some(offset),\n            _ => break,\n        }\n    }\n\n    if updated > 0 {\n        ::zeroclaw_log::record!(\n            INFO,\n            ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Note).with_attrs(\n                ::serde_json::json!({\n                    \"collection\": collection,\n                    \"updated\": updated,","sourceCodeStart":3244,"sourceCodeEnd":3280,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-config/src/schema/v2.rs#L3244-L3280","documentation":"The second network step of migrate_qdrant_collection_to_v3: after a successful scroll page, it POSTs the scrolled point ids to /collections/{collection}/points/payload to set payload agent_id = \"default\" (QDRANT_DEFAULT_AGENT_ID). This error fires when that set-payload call returns a non-2xx status; the message embeds the HTTP status and response text. Because scroll succeeded first, failures here are usually write-path issues: 403 read-only credentials, 409 collection is being optimized/locked, 429 rate limiting, or points deleted mid-migration (404 Not Found points).","triggerScenarios":"Qdrant API key valid for read but not write (403); concurrent migration or heavy optimization on the collection (409/503); rate-limited Qdrant Cloud tier (429); points removed by another client between scroll and set-payload; oversized batch rejected (413).","commonSituations":"Running the V3 upgrade on a live production Qdrant under load; read-only replica endpoints configured as base_url; shared Qdrant cluster with strict quotas; two ZeroClaw instances migrating the same collection simultaneously.","solutions":["Check the embedded status: 403 → grant the key write/update permissions on the collection; 429 → slow down or upgrade quota, then re-run (migration is idempotent)","Re-run migrate_qdrant_collection_to_v3 — already-updated points are skipped because the scroll filter only matches points lacking agent_id","Pause other heavy jobs (optimization, reindexing) on the collection during migration","Ensure base_url points at the primary node, not a read-only replica"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"let mut backoff = std::time::Duration::from_secs(1);\nfor attempt in 0..5 {\n    match migrate_qdrant_collection_to_v3(&client, &url, &coll, key).await {\n        Ok(n) => { println!(\"migrated {n} points\"); break; }\n        Err(e) if e.to_string().starts_with(\"Qdrant set payload failed\") && attempt < 4 => {\n            tokio::time::sleep(backoff).await; // 409/429 are transient\n            backoff *= 2;\n        }\n        Err(e) => return Err(e),\n    }\n}","preventionTips":["The migration is idempotent (only points lacking agent_id are touched) — always safe to re-run after a transient failure","Give the Qdrant key write access, not just read, before starting the V3 upgrade","Avoid running the migration during collection optimization or heavy ingest windows"],"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"}