clockworklabs/SpacetimeDB · error · anyhow::Error

Error resolving row type for view

Error message

Error resolving row type for view

What it means

Thrown while materializing the result of a one-off view call on the module host actor. The view's declared row type (row_type / product_type_ref from the module's BSATN typespace) either fails to resolve_refs() against the typespace or resolves to a type that is not a product (struct/row) type, so into_product() fails. In practice the module's type metadata and the view's declared return type disagree, which normally means a stale module definition is being used against mismatched module metadata.

Solutions

  1. Republish the module so database metadata, st_view rows, and the module definition all come from the same build
  2. Verify every view's declared row type is a product (row/struct) type, not an enum or scalar
  3. If it reproduces after a clean republish, minimize the module and report it as a SpacetimeDB issue
Defensive patterns

Strategy: validation

Validate before calling

// Before invoking view calls, verify the declared row type resolves to a product type
fn view_row_type_is_product(ts: &Typespace, row_type: AlgebraicTypeRef) -> bool {
    ts.resolve(row_type)
        .resolve_refs()
        .ok()
        .and_then(|ty| ty.into_product().ok())
        .is_some()
}

if !view_row_type_is_product(&typespace, view.product_type_ref) {
    return Err(anyhow::anyhow!("view {} row type does not resolve to a product; republish the module", view.name));
}

Try / catch

match call_view_result {
    Err(e) if e.to_string().contains("Error resolving row type for view") => {
        // Surface an actionable message: republish module, check view return type
    }
    other => other,
}

Prevention

When it happens

Trigger: Calling view evaluation on the module host actor where view_typespace.resolve(row_type).resolve_refs() errors, or the resolved AlgebraicType is not a product type - e.g. the view's return type was changed to an enum/sum type or a scalar, or the host holds a module definition from a different build than the one that registered the view.

Common situations: Publishing an updated module that changed a view's return type while old metadata is still in play; hand-built or corrupted modules with invalid BSATN bindings; version skew between host and module SDK.

Related errors


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

Appendix: source

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

            }
            // TODO: maybe do something else with user errors?
            (Err(ExecutionError::User(err)), _) => {
                inst.log_traceback("view", &view_name, &anyhow::anyhow!(err));
                self.handle_outer_error(&result.stats.energy, &view_name).into()
            }
            (Ok(raw), sender) => {
                // This is wrapped in a closure to simplify error handling.
                let outcome: Result<ViewOutcome, anyhow::Error> = (|| {
                    let view_call = match sender {
                        Some(sender) => ViewCallInfo::sender(view_id, sender),
                        None => ViewCallInfo::anonymous(view_id),
                    };
                    let result = ViewResult::from_return_data(raw).context("Error parsing view result")?;
                    let row_product_type = view_typespace
                        .resolve(row_type)
                        .resolve_refs()?
                        .into_product()
                        .map_err(|_| anyhow!("Error resolving row type for view"))?;

                    let rows = match result {
                        ViewResult::Rows(bytes) => deserialize_view_rows(row_type, bytes, &view_typespace)
                            .context("Error deserializing rows returned by view".to_string())?,
                        ViewResult::RawSql(query) => self
                            .run_query_for_view(&mut tx, &query, &row_product_type, &view_call)
                            .context("Error executing raw SQL returned by view".to_string())?,
                    };

                    let replica_ctx = inst.replica_ctx();
                    let stdb = replica_ctx.relational_db();
                    stdb.materialize_view_call(&mut tx, table_id, view_call, rows)
                        .context("Error materializing view")?;

                    Ok(ViewOutcome::Success)
                })();
                match outcome {
                    Ok(outcome) => outcome,

View on GitHub (pinned to eddf9f5014)