{"record":{"id":"265f0b39f14aea0d","repo":"nikivdev/code","slug":"open-jazz2-failed","errorCode":null,"errorMessage":"open jazz2 failed","messagePattern":"open jazz2 failed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/jazz_state.rs","lineNumber":95,"sourceCode":"    }\n\n    let db = Database::new(env);\n    save_catalog_id(&path, db.catalog_object_id())?;\n    Ok(db)\n}\n\nfn open_db_with_retry() -> Result<Database> {\n    let mut last_err: Option<anyhow::Error> = None;\n    for _ in 0..3 {\n        match open_db() {\n            Ok(db) => return Ok(db),\n            Err(err) => {\n                last_err = Some(err);\n                thread::sleep(Duration::from_millis(60));\n            }\n        }\n    }\n    Err(last_err.unwrap_or_else(|| anyhow::anyhow!(\"open jazz2 failed\")))\n}\n\nfn is_lock_error(err: &anyhow::Error) -> bool {\n    err.chain().any(|cause| {\n        let msg = cause.to_string().to_lowercase();\n        msg.contains(\"lock\") || msg.contains(\"resource temporarily unavailable\")\n    })\n}\n\npub fn state_dir() -> PathBuf {\n    if let Ok(path) = std::env::var(\"FLOW_JAZZ2_PATH\") {\n        return config::expand_path(&path);\n    }\n    let repo_root = config::expand_path(DEFAULT_REPO_ROOT);\n    if repo_root.exists() {\n        return repo_root.join(\".jazz2\");\n    }\n    std::env::var_os(\"HOME\")","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/nikivdev/code/blob/a747e741ae92c09071d0ae946ab48488adcff1ce/src/jazz_state.rs#L77-L113","documentation":"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.","triggerScenarios":"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).","commonSituations":"Concurrent CLI invocations contending on jazz2, stale lock from a killed process, read-only filesystem, DB file corrupted after a crash.","solutions":["Close other processes using jazz2 (other f invocations, DB browsers) and retry","Check file permissions and that the jazz2 file/directory are writable and not corrupt (try opening with sqlite3)","Increase retry count/backoff in open_db_with_retry for heavy concurrency","Restore or delete/recreate a corrupted jazz2 database"],"exampleFix":"// before\nErr(last_err.unwrap_or_else(|| anyhow::anyhow!(\"open jazz2 failed\")))\n// after\nErr(last_err.unwrap_or_else(|| anyhow::anyhow!(\"open jazz2 failed: unknown cause, check db file permissions and concurrent processes\")))","handlingStrategy":"retry","validationCode":"let db_path = std::path::Path::new(\"jazz2\");\nif !db_path.exists() { anyhow::bail!(\"jazz2 database missing\"); }\nlet meta = std::fs::metadata(db_path)?;\nif meta.permissions().readonly() { anyhow::bail!(\"jazz2 is read-only\"); }","typeGuard":null,"tryCatchPattern":"match with_db(|db| record_task_run(db, rec)) {\n    Err(e) if e.to_string().contains(\"open jazz2 failed\") || e.to_string().to_lowercase().contains(\"lock\") => {\n        std::thread::sleep(Duration::from_millis(500));\n        with_db(|db| record_task_run(db, rec))?; // one extra outer retry\n    }\n    other => other?,\n}","preventionTips":["Avoid running many concurrent f processes against the same jazz2","Add exponential backoff to open retries","Monitor for stale locks after killed processes"],"tags":["database","sqlite","lock"],"backgroundTag":"database-locked","analyzedSha":"a747e741ae92c09071d0ae946ab48488adcff1ce","analyzedAt":"2026-09-01T22:43:55.719Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}