openai/codex · error · io::Error

memory import requires the Codex state database

Error message

memory import requires the Codex state database

What it means

import() requires a live Codex state database handle and returns io::Error(NotConnected, 'memory import requires the Codex state database') when state_db is None (codex-rs/external-agent-migration/src/memory_import.rs:69-74). After copying memory files into codex_home/memories, the import enqueues a global memory consolidation through the state DB; without the handle there is no way to schedule it, so the call refuses rather than importing untracked files.

Source

Thrown at codex-rs/external-agent-migration/src/memory_import.rs:70

pub(super) async fn import(
    codex_home: &Path,
    external_agent_home: &Path,
    state_db: Option<&StateDbHandle>,
    selected_memory: &[String],
) -> io::Result<MemoryImportOutcome> {
    let selected_memory = selected_memory
        .iter()
        .map(String::as_str)
        .collect::<BTreeSet<_>>();
    if selected_memory.is_empty() {
        return Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            "memory import requires at least one selected memory",
        ));
    }
    let state_db = state_db.ok_or_else(|| {
        io::Error::new(
            io::ErrorKind::NotConnected,
            "memory import requires the Codex state database",
        )
    })?;
    let memory_root = codex_home.join("memories");
    codex_memories_write::workspace::prepare_memory_workspace(&memory_root)
        .await
        .map_err(io::Error::other)?;
    let memory_files = discover_external_memory_files(external_agent_home)?;
    let copy_outcome = copy_resources(codex_home, &memory_files, &selected_memory)?;
    if copy_outcome.workspace_changed
        && let Err(err) = state_db
            .memories()
            .enqueue_global_consolidation(chrono::Utc::now().timestamp())
            .await
    {
        tracing::warn!(error = %err, "failed to enqueue imported memory consolidation");
    }

View on GitHub (pinned to 339751715c)

Solutions

  1. Open the Codex state database for the target codex_home and pass Some(&handle) before importing
  2. If the DB open failed earlier in the flow, propagate that error instead of continuing with None
  3. In tests, create a StateDbHandle against a temp directory so import runs against real (temporary) state

Example fix

// before
let outcome = import(&codex_home, &external_home, None, &selected).await?; // NotConnected

// after
let state_db = StateDbHandle::open(&codex_home).await?; // or reuse the app's existing handle
let outcome = import(&codex_home, &external_home, Some(&state_db), &selected).await?;
Defensive patterns

Strategy: validation

Validate before calling

let Some(state_db) = state_db.as_ref() else {
    // open it or fail loudly - import cannot run without it
    anyhow::bail!("state database unavailable; cannot import memory");
};

Try / catch

match err.kind() {
    io::ErrorKind::NotConnected => { /* open/repair the state DB, then retry import */ }
    _ => return Err(err),
}

Prevention

When it happens

Trigger: Calling import(..., None /* state_db */, ...) - the handle was never opened, an earlier open failure was swallowed, or a test/CLI path forgot to construct the StateDbHandle.

Common situations: Refactors that changed import's signature leaving some caller passing None; migration run in a context where the state DB failed to open (locked, missing permissions, wrong codex_home); unit tests with a temp codex_home but no state DB.

Related errors


AI-assisted analysis of openai/codex@339751715c (2026-08-25). Data as JSON: /api/errors/c2a144a4dab8ace7. Report an issue: GitHub.