Hmbown/CodeWhale · error

Runtime directory override conflicts with the saved…

Error message

Runtime directory override conflicts with the saved session's Runtime store

What it means

When constructing the runtime thread manager with a saved RuntimeStoreBinding, any runtime_dir_override() (e.g. from an environment variable or CLI flag) must resolve to exactly the store directory recorded in the binding. It throws 'Runtime directory override conflicts with the saved session's Runtime store' when the override's checked root differs from binding.data_dir, preventing the manager from silently reading/writing a different store than the session's.

Solutions

  1. Unset the runtime directory override (env var / flag) so the session's saved data_dir is used.
  2. Point the override at the exact directory recorded in the session binding (the path from the error context).
  3. Delete/regenerate the session binding if you intend to migrate to the override directory as its new store.
  4. Check checked_runtime_store_root's resolution of the override (symlinks/canonicalization can make paths that look equal differ).

Example fix

// before: override conflicts with saved session
CODEWHALE_RUNTIME_DIR=/tmp/other-store app --resume session.json
// after: match the saved store or drop the override
unset CODEWHALE_RUNTIME_DIR && app --resume session.json
Defensive patterns

Strategy: validation

Validate before calling

// compare override and binding roots before constructing the manager
if let (Some(binding), Some(override_dir)) = (binding.as_ref(), runtime_dir_override()) {
    anyhow::ensure!(
        checked_runtime_store_root(override_dir)? == binding.data_dir,
        "runtime dir override conflicts with saved session store"
    );
}

Try / catch

match RuntimeThreadManager::new(manager_cfg, plugin_registry, binding.as_ref()).await {
    Ok(m) => m,
    Err(e) if e.to_string().contains("Runtime directory override conflicts") => {
        eprintln!("dropping override to honor the saved session store");
        RuntimeThreadManager::new(manager_cfg, plugin_registry, binding.as_ref()).await?
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Starting the manager with Some(binding) while a runtime directory override is set whose checked_runtime_store_root != binding.data_dir — e.g. CODEWHALE-style runtime dir env var pointing elsewhere while resuming a saved session.

Common situations: Developer has a runtime-dir env var exported globally but resumes an old session saved under a different directory; switching between dev/prod store directories while reusing a session file; running a second checkout whose default override differs from the session's store.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/1c358e71517a0224. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/runtime_threads.rs:5043

    pub fn open_with_plugin_registry(
        config: Config,
        workspace: PathBuf,
        manager_cfg: RuntimeThreadManagerConfig,
        plugin_registry: Arc<crate::plugins::PluginRegistry>,
    ) -> Result<Self> {
        Self::open_inner(config, workspace, manager_cfg, Some(plugin_registry), None)
    }

    pub(crate) fn open_for_session(
        config: Config,
        workspace: PathBuf,
        mut manager_cfg: RuntimeThreadManagerConfig,
        plugin_registry: Arc<crate::plugins::PluginRegistry>,
        binding: Option<&RuntimeStoreBinding>,
    ) -> Result<Self> {
        if let Some(binding) = binding {
            if let Some(override_dir) = runtime_dir_override() {
                anyhow::ensure!(
                    checked_runtime_store_root(override_dir)? == binding.data_dir,
                    "Runtime directory override conflicts with the saved session's Runtime store"
                );
            }
            if binding.is_missing_session_store()? {
                // Never claim the missing owner's scope. A fresh store cannot
                // execute its queued tasks, approvals, mail or automations.
                // All recovery attempts for this conversation contend on the
                // same host lock. Random paths would let two processes mint
                // competing owners before either saves the repaired binding.
                manager_cfg.data_dir = manager_cfg
                    .data_dir
                    .with_file_name("runtime-recovered-session");
                return Self::open_inner(
                    config,
                    workspace,
                    manager_cfg,
                    Some(plugin_registry),

View on GitHub (pinned to 73e0f67d83)