{"record":{"id":"8876f66db2cd8e3d","repo":"zeroclaw-labs/zeroclaw","slug":"memory-backend-qdrant-requires-a-storage-qdran","errorCode":null,"errorMessage":"memory backend 'qdrant' requires a `[storage.qdrant.<alias>]` entry referenced by `memory.backend = \"qdrant.<alias>\"`","messagePattern":"memory backend 'qdrant' requires a `\\[storage\\.qdrant\\.<alias>\\]` entry referenced by `memory\\.backend = \"qdrant\\.<alias>\"`","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-memory/src/lib.rs","lineNumber":681,"sourceCode":"                    dimensions: resolved_embedding.dimensions,\n                },\n                config.auto_reindex_on_identity_change,\n            );\n        }\n        Ok(mem)\n    }\n\n    // Per-backend SQLite open-timeout override comes from the active storage\n    // alias (V3); when no typed entry resolves, sqlite waits indefinitely.\n    let sqlite_open_timeout_secs = match active_storage {\n        ActiveStorage::Sqlite(sq) => sq.open_timeout_secs,\n        _ => None,\n    };\n\n    if matches!(backend_kind, MemoryBackendKind::Qdrant) {\n        let qdrant_cfg = match active_storage {\n            ActiveStorage::Qdrant(q) => q,\n            _ => anyhow::bail!(\n                \"memory backend 'qdrant' requires a `[storage.qdrant.<alias>]` entry \\\n                 referenced by `memory.backend = \\\"qdrant.<alias>\\\"`\"\n            ),\n        };\n        let url = qdrant_cfg\n            .url\n            .clone()\n            .filter(|s| !s.trim().is_empty())\n            .context(\"Qdrant memory backend requires `url` in [storage.qdrant.<alias>]\")?;\n        let collection = qdrant_cfg.collection.clone();\n        let qdrant_api_key = qdrant_cfg.api_key.clone().filter(|s| !s.trim().is_empty());\n        let embedder: Arc<dyn embeddings::EmbeddingProvider> =\n            Arc::from(embeddings::create_embedding_provider(\n                &resolved_embedding.model_provider,\n                resolved_embedding.api_key.as_deref(),\n                &resolved_embedding.model,\n                resolved_embedding.dimensions,\n            ));","sourceCodeStart":663,"sourceCodeEnd":699,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-memory/src/lib.rs#L663-L699","documentation":"The backend classified as qdrant, but the storage resolved from the config is not an ActiveStorage::Qdrant entry — the [storage.qdrant.<alias>] section referenced by memory.backend = \"qdrant.<alias>\" is missing or belongs to another storage family. The qdrant client needs that section's url (required, non-empty), collection, and api_key, so the factory bails with the exact TOML shape expected.","triggerScenarios":"`memory.backend = \"qdrant.prod\"` while `[storage.qdrant.prod]` does not exist: alias typo (prodd vs prod), the section written without the alias level ([storage.qdrant] instead of [storage.qdrant.prod]), or the alias defined only under a different family ([storage.postgres.prod]). Also fires for a bare backend = \"qdrant\" with no alias entry at all.","commonSituations":"Renaming storage aliases without updating memory.backend; environment overlay files that drop the [storage.*] section; merging config layers where storage and memory come from different sources.","solutions":["Add the matching section: `[storage.qdrant.<alias>]` with `url = \"http://host:6333\"` (plus optional collection and api_key), and keep `memory.backend = \"qdrant.<alias>\"` aligned.","Fix the alias typo so memory.backend's suffix exactly matches the TOML section name.","Check nesting: the alias is one level below the family, i.e. [storage.qdrant.prod], not [storage.qdrant] prod = ... in the wrong shape."],"exampleFix":"# before\n[memory]\nbackend = \"qdrant.prod\"\n\n# after\n[memory]\nbackend = \"qdrant.prod\"\n\n[storage.qdrant.prod]\nurl = \"http://localhost:6333\"\ncollection = \"zeroclaw_memories\"","handlingStrategy":"validation","validationCode":"let backend = backend_kind_from_dotted(&config.memory.backend);\nif backend == \"qdrant\"\n    && !matches!(config.resolve_active_storage(), ActiveStorage::Qdrant(_))\n{\n    anyhow::bail!(\n        \"memory.backend = {:?} has no matching [storage.qdrant.<alias>] section\",\n        config.memory.backend\n    );\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate the dotted alias against the storage tables at config load time, before any memory is constructed.","Generate environment configs from one template so [storage.qdrant.<alias>] and memory.backend always move together.","Add a CI smoke test that constructs memory for every environment config in the repo."],"tags":["qdrant","config","storage-alias","toplevel-config"],"backgroundTag":"missing-config-section","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}