zed-industries/zed · error

database not initialized

Error message

database not initialized

What it means

Database::global(cx) returns the per-App connection global set during startup, falling back to a shared LazyLock. The panic fires when no Database global was installed and the build is not test/test-support (those builds return TEST_APP_DATABASE first, which is why the code carries #[allow(unreachable_code)]). It means some code path queried the database before initialization ran — tests can pass while production panics.

Source

Thrown at crates/db/src/db.rs:88

    /// inventory-registered migrations in dependency order.
    #[cfg(any(test, feature = "test-support"))]
    pub fn test_new() -> Self {
        let name = format!("test-db-{}", uuid::Uuid::new_v4());
        let connection = gpui::block_on(open_test_db::<AppMigrator>(&name));
        Self(connection)
    }

    /// Returns the per-App connection if set, otherwise falls back to
    /// the shared LazyLock.
    pub fn global(cx: &App) -> &ThreadSafeConnection {
        #[allow(unreachable_code)]
        if let Some(db) = cx.try_global::<Self>() {
            return &db.0;
        } else {
            #[cfg(any(feature = "test-support", test))]
            return &TEST_APP_DATABASE.0;

            panic!("database not initialized")
        }
    }
}

fn topological_sort<'a>(registrations: &[&'a DomainMigration]) -> Vec<&'a DomainMigration> {
    let mut sorted: Vec<&DomainMigration> = Vec::new();
    let mut visited: std::collections::HashSet<&str> = std::collections::HashSet::new();

    fn visit<'a>(
        name: &str,
        registrations: &[&'a DomainMigration],
        sorted: &mut Vec<&'a DomainMigration>,
        visited: &mut std::collections::HashSet<&'a str>,
    ) {
        if visited.contains(name) {
            return;
        }
        if let Some(reg) = registrations.iter().find(|r| r.name == name) {

View on GitHub (pinned to f4178619ac)

Solutions

  1. Find the init that installs the global (cx.set_global of the Database wrapper) and run it during app startup, before any entity touches the db
  2. Copy the full init sequence into the new entrypoint
  3. In test binaries, ensure the test-support feature is enabled so TEST_APP_DATABASE is used
  4. Grep for Database::global callers reachable before init and reorder

Example fix

// before
fn main() {
    app.run(|cx| {
        let conn = db::Database::global(cx); // panic: database not initialized
    });
}

// after
fn main() {
    app.run(|cx| {
        cx.set_global(db::Database::open_default(cx)); // install the global first
        let conn = db::Database::global(cx);
    });
}
Defensive patterns

Strategy: validation

Validate before calling

use gpui::App;

fn ensure_database(cx: &mut App) {
    if cx.try_global::<db::Database>().is_none() {
        cx.set_global(db::Database::open_default(cx));
    }
}

Type guard

fn database_ready(cx: &App) -> bool {
    cx.try_global::<db::Database>().is_some()
}

Prevention

When it happens

Trigger: Calling Database::global before the startup code that does cx.set_global; a new entrypoint (CLI, embedder, plugin host) wired up without the db init sequence; init made conditional on a feature that is compiled out.

Common situations: Refactors moving init after first use; new binaries copying only part of the app bootstrap; tests green via TEST_APP_DATABASE while the shipped build crashes at first query.

Related errors


AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20). Data as JSON: /api/errors/9cd8f1f4f75bfc40. Report an issue: GitHub.