linera-io/linera-protocol · error

failed to create SQLite database file: {database_url}, error

Error message

failed to create SQLite database file: {database_url}, error: {e}

What it means

When the Linera indexer opens its SQLite database and the file does not yet exist, SqliteDb::new creates it with std::fs::File::create and panics if the OS call fails. The message includes the database path and the underlying io::Error, so the real cause (usually a missing parent directory, permission denied, or a read-only filesystem) is visible at the end of the panic output.

Source

Thrown at linera-indexer/lib/src/db/sqlite/mod.rs:76

}

pub struct SqliteDatabase {
    pool: SqlitePool,
}

impl SqliteDatabase {
    /// Creates a new SQLite database connection.
    pub async fn new(database_url: &str) -> Result<Self, SqliteError> {
        if !database_url.contains("memory") {
            match std::fs::exists(database_url) {
                Ok(true) => {
                    tracing::info!(?database_url, "opening existing SQLite database");
                }
                Ok(false) => {
                    tracing::info!(?database_url, "creating new SQLite database");
                    // Create the database file if it doesn't exist
                    std::fs::File::create(database_url).unwrap_or_else(|e| {
                        panic!("failed to create SQLite database file: {database_url}, error: {e}")
                    });
                }
                Err(e) => {
                    panic!(
                        "failed to check SQLite database existence. file: {database_url}, error: {e}"
                    )
                }
            }
        }
        let pool = SqlitePoolOptions::new()
            .max_connections(5)
            .connect(database_url)
            .await
            .map_err(SqliteError::Database)?;
        let db = Self { pool };
        db.initialize_schema().await?;
        Ok(db)
    }

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Create the parent directory: mkdir -p /path/to/data
  2. Make sure the directory is writable by the running user (chown/chmod or move the DB under $HOME or /tmp)
  3. Check the volume is mounted read-write and has free space (df)
  4. Re-run and confirm the new file appears; subsequent starts take the 'opening existing SQLite database' path

Example fix

# before
linera-indexer --database /var/lib/nonexistent-dir/indexer.db

# after
mkdir -p /var/lib/nonexistent-dir && chown "$USER" /var/lib/nonexistent-dir
linera-indexer --database /var/lib/nonexistent-dir/indexer.db
Defensive patterns

Strategy: validation

Validate before calling

let path = std::path::Path::new(database_url);
if let Some(parent) = path.parent() {
    std::fs::create_dir_all(parent)
        .unwrap_or_else(|e| panic!("cannot create {}: {e}", parent.display()));
}
assert!(
    parent.map(|p| p.writable()).unwrap_or(false) || path.writable(),
    "no write permission for {}",
    path.display()
);

Prevention

When it happens

Trigger: Launching the indexer with a --database path whose parent directory does not exist, is not writable by the current user, sits on a read-only mount, or when the disk is full. Only fires when the file is confirmed absent (Ok(false) from the existence check) and creation then fails.

Common situations: Pointing the indexer at /var/lib/... or other root-owned directories without mkdir/chown first; container deployments that mount an empty read-only volume; typos in the database path (e.g. a missing directory component); CI runs as an unprivileged user.

Related errors


AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22). Data as JSON: /api/errors/c0dadeb2d7f31403. Report an issue: GitHub.