clockworklabs/SpacetimeDB · error · DBError

database {} already initialized

Error message

database {} already initialized

What it means

RelationalDB::set_initialized records program metadata (identity, owner, program hash/bytes) in st_module. It errors when metadata already exists with a different program hash, database identity, or owner identity; the source marks this 'Probably a bug' because hosts should use the update/migrate path for already-initialized databases, not re-initialize.

Source

Thrown at crates/engine/src/relational_db.rs:444

    /// See [`Self::open`] for further information.
    pub fn set_initialized(&self, tx: &mut MutTx, program: Program) -> Result<(), DBError> {
        log::trace!(
            "[{}] DATABASE: set initialized owner={} program_hash={}",
            self.database_identity,
            self.owner_identity,
            program.hash
        );

        // Probably a bug: the database is already initialized.
        // Ignore if it would be a no-op.
        if let Some(meta) = self.inner.metadata_mut_tx(tx)? {
            if program.hash == meta.program_hash
                && self.database_identity == meta.database_identity
                && self.owner_identity == meta.owner_identity
            {
                return Ok(());
            }
            return Err(anyhow!("database {} already initialized", self.database_identity).into());
        }
        let row = StModuleRow {
            database_identity: self.database_identity.into(),
            owner_identity: self.owner_identity.into(),

            program_kind: program.kind,
            program_hash: program.hash,
            program_bytes: program.bytes,
            module_version: ONLY_MODULE_VERSION.into(),
        };
        Ok(tx.insert_via_serialize_bsatn(ST_MODULE_ID, &row).map(drop)?)
    }

    /// Obtain the [`Metadata`] of this database.
    ///
    /// `None` if the database is not yet fully initialized.
    pub fn metadata(&self) -> Result<Option<Metadata>, DBError> {
        Ok(self.with_read_only(Workload::Internal, |tx| self.inner.metadata(tx))?)

View on GitHub (pinned to 3653d2ed49)

Solutions

  1. Only call set_initialized when db.metadata()? returns None
  2. For an already-initialized database, route through the migration/update path instead of initialization
  3. If the existing database is disposable, drop and recreate it before initializing with the new program

Example fix

// before
let tx = db.begin_mut_tx(IsolationLevel::Serializable, Workload::Internal);
db.set_initialized(&mut tx, program)?;

// after: guard on existing metadata
if db.metadata()?.is_some() {
    anyhow::bail!("database already initialized; use the update path");
}
let mut tx = db.begin_mut_tx(IsolationLevel::Serializable, Workload::Internal);
db.set_initialized(&mut tx, program)?;
Defensive patterns

Strategy: validation

Validate before calling

// Guard set_initialized on existing metadata
match db.metadata()? {
    None => { /* safe to initialize */ }
    Some(meta) => {
        anyhow::ensure!(
            meta.program_hash == program.hash,
            "database already initialized with a different program; use the update path"
        );
        return Ok(());
    }
}
let mut tx = db.begin_mut_tx(IsolationLevel::Serializable, Workload::Internal);
db.set_initialized(&mut tx, program)?;

Type guard

fn is_uninitialized(db: &RelationalDB) -> bool {
    db.metadata().ok().flatten().is_none()
}

Prevention

When it happens

Trigger: Calling set_initialized on a database whose metadata row already exists and whose program_hash/kind or identities differ from the Program being installed; a host publish flow that picks the initialize branch instead of the update branch on re-publish.

Common situations: Host control-flow bug choosing init instead of migrate during republish; test harnesses calling init twice with different schemas; publishing a different module binary where an update was intended.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@3653d2ed49 (2026-08-20). Data as JSON: /api/errors/86fc74cb91dc7c5c. Report an issue: GitHub.