BigPizzaV3/CodexPlusPlus · error

sidebar catalog database is not an allowed Codex database

Error message

sidebar catalog database is not an allowed Codex database

What it means

Each sidebar catalog entry's db_path, after canonicalization, must be present in the allowlist of Codex database paths. This error blocks restore operations against any SQLite file that is not a recognized Codex database, guarding against arbitrary-file overwrites.

Solutions

  1. Set db_path to the actual Codex sessions database location for this machine (let the app re-derive it or fix the JSON)
  2. Remove symlinks in the path so canonicalize() yields the expected directory, or update the allowlist source to include the new canonical location
  3. If the state came from another machine, re-sync sidebar state locally instead of restoring the foreign db_path

Example fix

// before
{"table":"threads","db_path":"C:\\old\\sessions\\state.db"}
// after
{"table":"threads","db_path":"C:\\Users\\me\\.codex\\sessions\\state.db"}
Defensive patterns

Strategy: validation

Validate before calling

let canonical = std::fs::canonicalize(&db_path)?;
if !allowed_paths.contains(&canonical) {
    eprintln!("db_path {} is not an allowed Codex database", canonical.display());
}

Type guard

fn allowed_db(p: &Path, allowed: &[PathBuf]) -> bool {
    p.canonicalize().map(|c| allowed.contains(&c)).unwrap_or(false)
}

Try / catch

if let Err(e) = restore(&state) {
    if e.to_string().contains("not an allowed Codex database") {
        // re-derive db_path locally and rewrite the entry before retrying
    }
}

Prevention

When it happens

Trigger: Restoring sidebar state where an entry's 'db_path' canonicalizes to a path not in allowed_paths (external DB, symlinked path, moved session storage, or path spelled differently from the canonical form).

Common situations: User relocated the Codex sessions directory; db_path contains a symlink or relative path resolving elsewhere; state file copied between machines with different user homes.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19). Data as JSON: /api/errors/7281ecdd08441d59. Report an issue: GitHub.

Appendix: source

Thrown at crates/codex-plus-data/src/provider_sync.rs:2718

            .as_array()
            .ok_or_else(|| anyhow::anyhow!("sidebar snapshot catalog must be an array"))?;
        let allowed_paths = sidebar_catalog_db_paths(codex_home)?;
        for entry in entries {
            let table = entry
                .get("table")
                .and_then(Value::as_str)
                .ok_or_else(|| anyhow::anyhow!("sidebar catalog entry is missing table"))?;
            if !SIDEBAR_CATALOG_TABLES.contains(&table) {
                anyhow::bail!("unsupported sidebar catalog table: {table}");
            }
            let path = entry
                .get("db_path")
                .and_then(Value::as_str)
                .map(PathBuf::from)
                .ok_or_else(|| anyhow::anyhow!("sidebar catalog entry is missing db_path"))?;
            let canonical = fs::canonicalize(&path)?;
            if !allowed_paths.contains(&canonical) {
                anyhow::bail!("sidebar catalog database is not an allowed Codex database");
            }
            let rows = entry
                .get("rows")
                .and_then(Value::as_array)
                .ok_or_else(|| anyhow::anyhow!("sidebar catalog entry rows must be an array"))?;
            for row in rows {
                let row_id = row
                    .get("thread_id")
                    .and_then(Value::as_str)
                    .ok_or_else(|| anyhow::anyhow!("sidebar catalog row is missing thread_id"))?;
                if row_id != thread_id {
                    anyhow::bail!("sidebar catalog row thread_id does not match snapshot");
                }
            }
        }
    }
    Ok(())
}

View on GitHub (pinned to b1ed92e5e4)