{"record":{"id":"595483b51ab4cebc","repo":"zeroclaw-labs/zeroclaw","slug":"flag-true-requires-memory-backend-sqlite","errorCode":null,"errorMessage":"{flag} = true requires memory.backend = \"sqlite\" (typed memory storage is SQLite-only), but memory.backend = {:?}","messagePattern":"(.+?) = true requires memory\\.backend = \"sqlite\" \\(typed memory storage is SQLite-only\\), but memory\\.backend = (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-memory/src/lib.rs","lineNumber":1007,"sourceCode":"    let backend_kind = agent_cfg.memory.backend;\n\n    // Typed-memory producers are SQLite-only. Config::validate already\n    // rejects this combination on every save path, but boot is\n    // deliberately validation-resilient (a hand-edited config still\n    // starts the daemon so the operator can repair it via /config), so\n    // enforce again here: failing agent-memory construction is an\n    // operator-visible startup error and keeps background consolidation\n    // from ever running typed writes into a backend that would reject\n    // them deep inside spawned work.\n    if config.memory.types.enabled || config.memory.consolidation_extract_facts {\n        let flag = if config.memory.types.enabled {\n            \"memory.types.enabled\"\n        } else {\n            \"memory.consolidation_extract_facts\"\n        };\n        let global_kind = backend_kind_from_dotted(&config.memory.backend);\n        if global_kind != \"sqlite\" {\n            anyhow::bail!(\n                \"{flag} = true requires memory.backend = \\\"sqlite\\\" (typed memory storage is SQLite-only), but memory.backend = {:?}\",\n                config.memory.backend\n            );\n        }\n        if !matches!(backend_kind, ConfigBackend::Sqlite) {\n            anyhow::bail!(\n                \"{flag} = true requires every agent on the sqlite memory backend (typed memory storage is SQLite-only), but agents.{agent_alias}.memory.backend = {backend_kind:?}\"\n            );\n        }\n    }\n\n    // Markdown branch: the wrapper composes per-agent dirs, not a\n    // shared backend. Skip the inner-backend factory entirely, but still\n    // apply the install-wide policy decorator to own and peer Markdown\n    // stores before composition.\n    if matches!(backend_kind, ConfigBackend::Markdown) {\n        let own_workspace = config.agent_workspace_dir(agent_alias);\n        let own: Arc<dyn Memory> = Arc::new(ScannedMemory::new(","sourceCodeStart":989,"sourceCodeEnd":1025,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-memory/src/lib.rs#L989-L1025","documentation":"Typed memory features (memory.types.enabled = true or memory.consolidation_extract_facts = true) persist typed rows in SQLite only. create_memory_for_agent refuses to construct the agent's memory when such a flag is set but the global memory.backend is not sqlite, rather than silently dropping typed data. The message interpolates the exact flag that tripped (memory.types.enabled or memory.consolidation_extract_facts).","triggerScenarios":"Calling create_memory_for_agent with a typed flag enabled while memory.backend is \"lucid\", \"qdrant\", \"markdown\", or \"none\" (backend_kind_from_dotted of the global backend != \"sqlite\").","commonSituations":"Enabling fact extraction/consolidation on deployments that run lucid for vector recall; merging config layers where one layer sets typed flags and another sets the backend; copying a typed-memory example config onto an existing non-sqlite deployment.","solutions":["Set `memory.backend = \"sqlite\"` if typed memory is required.","Disable the flagged features (`memory.types.enabled = false`, `memory.consolidation_extract_facts = false`) if the current backend must stay.","Audit the merged config for which layer set the flag — the message names the specific flag."],"exampleFix":"# before\n[memory]\nbackend = \"lucid\"\ntypes.enabled = true\n\n# after\n[memory]\nbackend = \"sqlite\"\ntypes.enabled = true","handlingStrategy":"validation","validationCode":"// Mirror the factory's rule before calling create_memory_for_agent\n// (TOML: memory.types.enabled / memory.consolidation_extract_facts)\nlet typed_enabled = config.memory.types_enabled || config.memory.consolidation_extract_facts;\nif typed_enabled && backend_kind_from_dotted(&config.memory.backend) != \"sqlite\" {\n    anyhow::bail!(\n        \"typed-memory flags require memory.backend = \\\"sqlite\\\"; current: {:?}\",\n        config.memory.backend\n    );\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate typed-memory flags against the global backend in a config lint step at startup.","Document next to each typed-memory flag that it is SQLite-only so operators do not combine it with lucid/qdrant.","When merging config layers, re-run the lint on the merged result, not on individual layers."],"tags":["config","validation","sqlite","typed-memory","consolidation"],"backgroundTag":"config-constraint-violation","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}