clockworklabs/SpacetimeDB · error · anyhow::Error

view not found in module_def

Error message

view {} not found in module_def

What it means

Raised in collect_subscribed_view_calls while building the list of view calls used to refresh subscribed views after a mutation. The code iterates module_def.all_views_with_prefix() and then re-looks each view up by its joined canonical name via view_by_name_with_global_fn_ptr; the lookup failing means the module definition's own name-to-view index disagrees with its view list. This is an internal invariant violation inside ModuleDef, not a user input error.

Solutions

  1. Update to a matched SpacetimeDB host/SDK version pair and republish the module
  2. Rebuild the module with the standard toolchain (spacetime build) so ModuleDef and its name index are generated consistently
  3. Reproduce with a minimal module and file a bug - this path indicates an internal ModuleDef inconsistency
Defensive patterns

Strategy: validation

Validate before calling

// Sanity-check ModuleDef name-index consistency before running mutations
for (prefix, _, view) in module_def.all_views_with_prefix() {
    let name = prefix.join(view.name.clone());
    if module_def.view_by_name_with_global_fn_ptr(&name).is_none() {
        return Err(anyhow::anyhow!("ModuleDef name index inconsistent for view {name}; rebuild the module"));
    }
}

Try / catch

match collect_result {
    Err(e) if e.to_string().contains("not found in module_def") => {
        // Internal invariant failure: rebuild/re-publish the module, then retry once
    }
    other => other,
}

Prevention

When it happens

Trigger: Any mutation that triggers subscribed-view refresh (e.g. SQL DML going through call_views_with_tx) when prefix.join(local_name) produces a name that view_by_name_with_global_fn_ptr cannot resolve - e.g. empty or colliding view local names after prefix joining, or a corrupted/hand-generated module definition.

Common situations: Custom or pre-release module builds; SDK and host version skew; essentially unreachable for modules built with the standard toolchain.

Related errors


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

Appendix: source

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

    owner_identity: Identity,
) -> Result<Vec<CallViewParams>, anyhow::Error> {
    let mut view_calls = Vec::new();

    for (prefix, owning_def, view) in module_def.all_views_with_prefix() {
        let ViewDef {
            name: local_name,
            is_anonymous,
            product_type_ref,
            ..
        } = view;

        // Full namespaced canonical name: matches both the st_view registration
        // (create_view / create_view_with_prefix) and `view_by_name_with_global_fn_ptr`.
        let view_name = prefix.join(local_name.clone());

        let (global_fn_ptr, _, _) = module_def
            .view_by_name_with_global_fn_ptr(&view_name)
            .ok_or_else(|| anyhow::anyhow!("view {} not found in module_def", view_name))?;

        let st_view = tx
            .view_from_name(&view_name)?
            .ok_or_else(|| anyhow::anyhow!("view {} not found in database", view_name))?;

        let view_id = st_view.view_id;
        let table_id = st_view
            .table_id
            .ok_or_else(|| anyhow::anyhow!("view {} does not have a backing table in database", view_name))?;
        let subs = tx.materialized_view_instances_for_view(view_id);
        let view_typespace = Arc::new(owning_def.typespace().clone());

        if *is_anonymous {
            if subs.is_empty() {
                continue;
            }
            view_calls.push(CallViewParams {
                view_name: view_name.clone(),

View on GitHub (pinned to eddf9f5014)