clockworklabs/SpacetimeDB · error · UpdateDatabaseResult::ErrorExecutingMigration

Trapped while evaluating views during database update

Error message

Trapped while evaluating views during database update

What it means

During a database update (publish/migration), when the update engine requests subscribed-view evaluation, the host runs the views inside the update transaction. If any view traps — a wasm trap or panic while executing view code — this message is produced, the transaction is rolled back (with metrics reported), and the update fails as ErrorExecutingMigration. The database keeps its pre-update state; no partial migration is committed.

Source

Thrown at crates/core/src/host/wasm_common/module_host_actor.rs:732

                    tx_offset
                };
                let durable_offset = stdb.durable_tx_offset();

                let res: UpdateDatabaseResult = match res {
                    crate::db::update::UpdateResult::Success => {
                        let tx_offset = succeed(self.info.clone(), FunctionBudget::ZERO, Duration::ZERO, tx);
                        UpdateDatabaseResult::UpdatePerformed {
                            tx_offset,
                            durable_offset,
                        }
                    }
                    crate::db::update::UpdateResult::EvaluateSubscribedViews => {
                        let (out, _, trapped) = self.evaluate_subscribed_views(tx, inst)?;
                        tx = out.tx;
                        if trapped || out.outcome != ViewOutcome::Success {
                            let msg = match trapped {
                                true => "Trapped while evaluating views during database update".to_string(),
                                false => format!(
                                    "Views evaluation did not complete successfully during database update: {:?}",
                                    out.outcome
                                ),
                            };

                            let (_, tx_metrics, reducer) = stdb.rollback_mut_tx(tx);
                            stdb.report_mut_tx_metrics(reducer, tx_metrics, None);
                            UpdateDatabaseResult::ErrorExecutingMigration(anyhow::anyhow!(msg))
                        } else {
                            let tx_offset =
                                succeed(self.info.clone(), out.execution_budget_used, out.total_duration, tx);
                            UpdateDatabaseResult::UpdatePerformed {
                                tx_offset,
                                durable_offset,
                            }
                        }
                    }

View on GitHub (pinned to 524b4487d9)

Solutions

  1. Identify the trapping view from the update error context and host logs, then reproduce it against a copy of the production data.
  2. Make view code total: replace unwrap/expect and unchecked indexing with handled cases.
  3. Fix the migration so the data view code sees matches its expectations, or stage the view change in a later publish.
  4. Retry the publish after the fix — the rollback guarantees no partial state from the failed attempt.

Example fix

// before: view traps on empty state
fn view(ctx: &ViewContext) -> Vec<JobRow> {
    let first = ctx.table::<Job>().iter().next().unwrap();
    vec![first.into()]
}

// after: tolerate the empty case instead of trapping
fn view(ctx: &ViewContext) -> Vec<JobRow> {
    ctx.table::<Job>().iter().take(1).map(Into::into).collect()
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Before publishing an update, run all views against a restored snapshot
for view in module.views() {
    evaluate_view(view, snapshot_db.clone())?; // must not trap on migrated data
}

Try / catch

match update_result {
    UpdateDatabaseResult::ErrorExecutingMigration(e) => {
        // transaction was rolled back automatically — fix the trapping view, then republish
        log::warn!("update rejected: {e:#}");
    }
    other => { /* ... */ }
}

Prevention

When it happens

Trigger: Publishing an update where materialized/subscribed view code traps during the post-migration evaluation pass: view code that unwraps None, indexes out of bounds, or otherwise aborts when run against the migrated data.

Common situations: Views written against the old schema shape running once against new data during migration; views assuming non-empty tables or particular column values; migrations leaving data in a state the view code does not handle.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16). Data as JSON: /api/errors/105d901d539dbb60. Report an issue: GitHub.