clockworklabs/SpacetimeDB · error

`close` was called on this `NoDurability` instance

Error message

`close` was called on this `NoDurability` instance

What it means

NoDurability is the Durability implementation used when no commitlog is configured (e.g. dev/standalone mode). close() sets an AtomicBool (Relaxed ordering) and append_tx checks it, panicking on append-after-close because the transaction would otherwise be silently dropped; it fails loudly instead. Hitting it means a commit raced shutdown: append_tx ran after close() had been called on the same instance.

Source

Thrown at crates/durability/src/imp/mod.rs:46

    }

    impl<T> Default for NoDurability<T> {
        fn default() -> Self {
            let (durable_offset, _) = watch::channel(None);
            Self {
                durable_offset,
                closed: AtomicBool::new(false),
                _txdata: PhantomData,
            }
        }
    }

    impl<T: Send + Sync> Durability for NoDurability<T> {
        type TxData = T;

        fn append_tx(&self, _: PreparedTx<Self::TxData>) {
            if self.closed.load(Ordering::Relaxed) {
                panic!("`close` was called on this `NoDurability` instance");
            }
        }

        fn durable_tx_offset(&self) -> DurableOffset {
            self.durable_offset.subscribe().into()
        }

        fn close(&self) -> Close {
            self.closed.store(true, Ordering::Relaxed);
            future::ready(*self.durable_offset.borrow()).boxed()
        }
    }
}

View on GitHub (pinned to 6dee26c6ef)

Solutions

  1. Quiesce committers first: stop accepting commits and await all in-flight commit tasks before calling close().
  2. In tests, join outstanding write futures (task tracker) before teardown.
  3. Upgrade spacetimedb: shutdown-ordering races here are treated as bugs and get patched.

Example fix

// before: close while commits may still land
durability.close().await;

// after: quiesce writers first, then close
commit_workers.shutdown().await; // joins all append_tx futures
durability.close().await;
Defensive patterns

Strategy: validation

Validate before calling

// shutdown ordering: quiesce committers before closing durability
commit_pool.shutdown().await; // joins outstanding append_tx futures, no new commits after
durability.close().await;

Prevention

When it happens

Trigger: Durability::close() on NoDurability followed by another Durability::append_tx, e.g. a commit worker still draining while shutdown starts, or a test closing the datastore then committing.

Common situations: Standalone/test runs without a commitlog; test harness teardown ordering that closes durability before joining commit futures; shutdown-ordering regressions.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@6dee26c6ef (2026-08-20). Data as JSON: /api/errors/76558b045c7a1cd3. Report an issue: GitHub.