nikivdev/code · error

open jazz2 failed

Error message

open jazz2 failed

What it means

open_db_with_retry retries opening the jazz2 SQLite database on lock errors (sleeping 60ms between attempts); if all retries fail, it returns the last error, or this error when no error was captured. It indicates the database could not be opened after exhausting retries.

Source

Thrown at src/jazz_state.rs:95

    }

    let db = Database::new(env);
    save_catalog_id(&path, db.catalog_object_id())?;
    Ok(db)
}

fn open_db_with_retry() -> Result<Database> {
    let mut last_err: Option<anyhow::Error> = None;
    for _ in 0..3 {
        match open_db() {
            Ok(db) => return Ok(db),
            Err(err) => {
                last_err = Some(err);
                thread::sleep(Duration::from_millis(60));
            }
        }
    }
    Err(last_err.unwrap_or_else(|| anyhow::anyhow!("open jazz2 failed")))
}

fn is_lock_error(err: &anyhow::Error) -> bool {
    err.chain().any(|cause| {
        let msg = cause.to_string().to_lowercase();
        msg.contains("lock") || msg.contains("resource temporarily unavailable")
    })
}

pub fn state_dir() -> PathBuf {
    if let Ok(path) = std::env::var("FLOW_JAZZ2_PATH") {
        return config::expand_path(&path);
    }
    let repo_root = config::expand_path(DEFAULT_REPO_ROOT);
    if repo_root.exists() {
        return repo_root.join(".jazz2");
    }
    std::env::var_os("HOME")

View on GitHub (pinned to a747e741ae)

Solutions

  1. Close other processes using jazz2 (other f invocations, DB browsers) and retry
  2. Check file permissions and that the jazz2 file/directory are writable and not corrupt (try opening with sqlite3)
  3. Increase retry count/backoff in open_db_with_retry for heavy concurrency
  4. Restore or delete/recreate a corrupted jazz2 database

Example fix

// before
Err(last_err.unwrap_or_else(|| anyhow::anyhow!("open jazz2 failed")))
// after
Err(last_err.unwrap_or_else(|| anyhow::anyhow!("open jazz2 failed: unknown cause, check db file permissions and concurrent processes")))
Defensive patterns

Strategy: retry

Validate before calling

let db_path = std::path::Path::new("jazz2");
if !db_path.exists() { anyhow::bail!("jazz2 database missing"); }
let meta = std::fs::metadata(db_path)?;
if meta.permissions().readonly() { anyhow::bail!("jazz2 is read-only"); }

Try / catch

match with_db(|db| record_task_run(db, rec)) {
    Err(e) if e.to_string().contains("open jazz2 failed") || e.to_string().to_lowercase().contains("lock") => {
        std::thread::sleep(Duration::from_millis(500));
        with_db(|db| record_task_run(db, rec))?; // one extra outer retry
    }
    other => other?,
}

Prevention

When it happens

Trigger: Opening src/jazz2 while another process holds an exclusive lock beyond the retry window, corrupt DB file, permission denied, or directory missing — so every open attempt fails and the loop exits with last_err set (or None).

Common situations: Concurrent CLI invocations contending on jazz2, stale lock from a killed process, read-only filesystem, DB file corrupted after a crash.

Related errors


AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01). Data as JSON: /api/errors/265f0b39f14aea0d. Report an issue: GitHub.