clockworklabs/SpacetimeDB · error
database ownership changed before publication
Error message
database ownership changed before publication
What it means
When updating an existing database, standalone verifies the publisher's identity equals the database's stored owner_identity before applying the new program. If the owner differs — meaning ownership was reassigned or the row changed since the caller last read it — the ensure! aborts the publication with this message so a non-owner cannot overwrite the module.
Solutions
- Publish using the identity that owns the database (the original publisher's key/credentials).
- If ownership legitimately changed, verify the new owner_identity on the server and publish as that owner.
- Transfer or recreate the database under the identity you intend to publish with.
Example fix
// before: publishing with wrong identity
await client.publish(db, program, { identity: devIdentity }); // not owner
// after: publish as owner
await client.publish(db, program, { identity: ownerIdentity }); Defensive patterns
Strategy: validation
Validate before calling
// verify ownership before publishing
const db = await client.getDatabase(dbIdentity);
if (db && db.owner_identity !== myIdentity) throw new Error('not the database owner'); Type guard
const isOwner = (db, identity) => db == null || db.owner_identity === identity;
Try / catch
try { publish(); } catch (e) { if (e.message.includes('ownership changed')) { switchToOwnerCredentials(); retry(); } else throw e; } Prevention
- Publish with the same identity that created the database
- Track ownership transfers and update deploy credentials
- Keep service identities consistent across CI jobs
When it happens
Trigger: Calling publish_database for an existing database with a publisher identity that differs from database.owner_identity, e.g. publishing under a different identity/key after the database was transferred or created by another account.
Common situations: A teammate tries to publish a database owned by another identity; switching local keys/credentials between publishes; automated jobs running with the wrong service identity.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- Database ` ` does not exist
- database ownership changed before deletion
- database ownership changed before reset
- initial publication requires a module and cannot require an…
- The database is not registered to the identity you…
AI-assisted analysis of clockworklabs/SpacetimeDB@eddf9f5014 (2026-09-20).
Data as JSON: /api/errors/c4ceb4f98b2245af.
Report an issue: GitHub.
Appendix: source
Thrown at crates/standalone/src/lib.rs:336
let program_hash = self.program_store.put(&spec.program_bytes).await?;
debug_assert_eq!(_hash_for_assert, program_hash);
let (database, replica) =
self.control_db
.upsert_database_with_environment(database, None, environment, &[])?;
// The leader nomination and input are durable already. If this
// waiter is cancelled, ordinary lookup resumes the same input.
self.on_insert_replica(&replica).await?;
debug_assert_eq!(database.id, replica.database_id);
Ok(None)
}
// The database already exists, so we'll try to update it.
// If that fails, we'll keep the old one.
Some(database) => {
anyhow::ensure!(
database.owner_identity == *publisher,
"database ownership changed before publication"
);
let database_id = database.id;
let database_identity = database.database_identity;
let leader = self.leader(database_id).await?;
let update_result = leader
.update(
database,
spec.host_type,
spec.program_bytes.to_vec().into(),
policy,
update,
spec.expected_module_version,
)
.await?;
if update_result.was_successful() {View on GitHub (pinned to eddf9f5014)