t8y2/dbx · critical

Failed to open storage

Error message

Failed to open storage

What it means

Panics/aborts in dbx-web main during startup when opening the application storage (database under DBX_DATA_DIR) fails — the storage layer could not be initialized (unwritable data directory, locked database file, or corrupted store). The web server refuses to start without working persistence.

Source

Thrown at crates/dbx-web/src/main.rs:304

    tracing_subscriber::fmt()
        .with_env_filter(
            tracing_subscriber::EnvFilter::try_from_default_env()
                .unwrap_or_else(|_| "dbx_web=info,tower_http=info".parse().unwrap()),
        )
        .init();

    rustls::crypto::aws_lc_rs::default_provider().install_default().expect("Failed to install rustls crypto provider");

    // Data directory
    let data_dir = std::env::var("DBX_DATA_DIR").map(std::path::PathBuf::from).unwrap_or_else(|_| {
        let home = std::env::var("HOME").unwrap_or_else(|_| ".".to_string());
        std::path::PathBuf::from(home).join(".dbx-web")
    });
    std::fs::create_dir_all(&data_dir).expect("Failed to create data directory");

    let app_state = {
        let db_path = data_dir.join("dbx.db");
        let storage = Storage::open(&db_path).await.expect("Failed to open storage");
        storage.migrate_from_json(&data_dir).await.expect("Failed to migrate JSON data");

        // Initialize core dialect registry and load external plugin dialects
        register_core_dialects();
        let registry = DialectRegistry::global();
        let plugin_dirs = vec![data_dir.join("plugins").join("dialects")];
        let load_result = DialectPluginLoader::scan_and_load(registry, &plugin_dirs);
        log::info!(
            "Dialect plugins loaded: {} success, {} errors, {} skipped",
            load_result.loaded.len(),
            load_result.errors.len(),
            load_result.skipped.len()
        );

        // Start dialect YAML hot-reload watcher
        let watch_dirs = plugin_dirs.clone();
        tokio::spawn(async move {
            if let Err(e) = DialectHotReload::run_forever(watch_dirs, DialectRegistry::global()).await {

View on GitHub (pinned to c0390bff16)

Solutions

  1. Check that no other dbx-web process is using dbx.db and that the file/directory is writable.
  2. Verify disk space and inode availability on the data volume.
  3. If the database is corrupted, restore from backup or move dbx.db aside to re-initialize (losing local data).
  4. Run migrations/schema fixes from the same or newer dbx version; avoid downgrading across schema changes.
  5. Wrap Storage::open in error handling that logs the underlying SQLite error instead of a bare panic.

Example fix

// before
let storage = Storage::open(&db_path).await.expect("Failed to open storage");
// after
let storage = Storage::open(&db_path)
    .await
    .unwrap_or_else(|e| panic!("Failed to open storage at {}: {e}", db_path.display()));
Defensive patterns

Strategy: try-catch

Validate before calling

let db_path = data_dir.join("dbx.db");
let db_ok = std::path::Path::new(&db_path).map(|p| !p.exists() || p.metadata().map(|m| m.is_file()).unwrap_or(false)).unwrap_or(false)
    && data_dir_writable(&data_dir);

Try / catch

let storage = match Storage::open(&db_path).await {
    Ok(s) => s,
    Err(e) => { eprintln!("Failed to open storage {}: {e}", db_path.display()); std::process::exit(1); }
};

Prevention

When it happens

Trigger: Storage::open(&db_path) fails when the data directory is unwritable, the SQLite file is corrupted or locked, disk is full, or the db file format is incompatible with the current rusqlite/sqlx version.

Common situations: Corrupted dbx.db after a crash or disk-full event; another dbx-web instance holding the SQLite lock; wrong ownership on a mounted volume; upgrading across an incompatible database schema version.

Related errors


AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05). Data as JSON: /api/errors/94b855b13564d12f. Report an issue: GitHub.