zeroclaw-labs/zeroclaw · error

memory backend 'none' disables persistence; choose sqlite, l

Error message

memory backend 'none' disables persistence; choose sqlite, lucid, or markdown before migration

What it means

create_memory_for_migration builds the operator memory store used by bulk import/export and CLI migration tooling. A memory.backend of "none" disables persistence entirely, so migration has nowhere to read rows from or write rows to. The factory rejects it up front and names the backends migration supports: sqlite, lucid, markdown.

Source

Thrown at crates/zeroclaw-memory/src/lib.rs:902

            }
            Err(e) => {
                ::zeroclaw_log::record!(
                    WARN,
                    ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Note)
                        .with_outcome(::zeroclaw_log::EventOutcome::Failure)
                        .with_attrs(::serde_json::json!({"error": format!("{e}")})),
                    "memory: background re-embed after embedding identity change failed; \
                     run `zeroclaw memory reindex` to retry"
                );
            }
        }
    });
}

pub fn create_memory_for_migration(config: &Config) -> anyhow::Result<Box<dyn Memory>> {
    let backend = backend_kind_from_dotted(&config.memory.backend);
    if matches!(classify_memory_backend(&backend), MemoryBackendKind::None) {
        anyhow::bail!(
            "memory backend 'none' disables persistence; choose sqlite, lucid, or markdown before migration"
        );
    }

    // Operator surface (bulk import + CLI management): writes are still
    // scanned and logged, but flagged rows are persisted rather than
    // rejected so an import never stops partway through, and read-time
    // withholding is disabled so `memory list` / `get` show every stored
    // row for inspection and removal. The runtime factory
    // (`create_memory_with_storage_and_routes`) applies the configured
    // `[memory.policy]`, so flagged rows remain withheld from recall
    // wherever `threat_scan_load_time` is enabled.
    let policy = MemoryPolicyConfig {
        threat_scan_on_hit: "block-on-read".into(),
        threat_scan_load_time: false,
        ..MemoryPolicyConfig::default()
    };

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Point the command at a config with a persistent backend: `memory.backend = "sqlite"` (or "lucid"/"markdown", optionally with a storage alias).
  2. If persistence is intentionally disabled for this deployment, skip migration/import tooling for it entirely.

Example fix

# before
[memory]
backend = "none"

# after
[memory]
backend = "sqlite"
Defensive patterns

Strategy: validation

Validate before calling

if backend_kind_from_dotted(&config.memory.backend) == "none" {
    anyhow::bail!(
        "cannot run migration/import with memory.backend = \"none\"; \
         switch to sqlite, lucid, or markdown first"
    );
}

Prevention

When it happens

Trigger: Running a migration or CLI import command while the active Config has `memory.backend = "none"`. The check uses backend_kind_from_dotted, so both bare "none" and a dotted form that classifies as none trip it.

Common situations: Dev or privacy-hardened profiles that disable memory being reused for an operational command; forgetting to switch config before running migration tooling; a shared default config that sets none for safety.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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