{"record":{"id":"2448e91f856f3333","repo":"clockworklabs/SpacetimeDB","slug":"view-does-not-have-a-backing-table","errorCode":null,"errorMessage":"view {:?} does not have a backing table","messagePattern":"view (.+?) does not have a backing table","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/core/src/host/module_host.rs","lineNumber":1177,"sourceCode":"    /// type-index references in the `ViewDef`.\n    pub owning_def: &'a ModuleDef,\n}\n\n/// Lookup a module's [`ViewDef`] and check for consistency among\n/// its readset, `st_view`, and the [`ModuleDef`].\npub(crate) fn resolve_view_for_refresh<'a>(\n    tx: &MutTxId,\n    module_def: &'a ModuleDef,\n    view_call: &ViewCallInfo,\n) -> anyhow::Result<ResolvedViewForRefresh<'a>> {\n    let st_view = tx\n        .lookup_st_view(view_call.view_id)\n        .with_context(|| format!(\"failed to look up view {}\", view_call.view_id))?;\n\n    let view_id = st_view.view_id;\n    let table_id = st_view\n        .table_id\n        .ok_or_else(|| anyhow::anyhow!(\"view {:?} does not have a backing table\", view_id))?;\n\n    let (global_fn_ptr, view_def, owning_def) = module_def\n        .view_by_name_with_global_fn_ptr(&st_view.view_name.clone().into())\n        .ok_or_else(|| {\n            anyhow::anyhow!(\n                \"view `{}` for view id `{}` not found in current module\",\n                st_view.view_name,\n                view_id\n            )\n        })?;\n\n    let is_anonymous = view_def.is_anonymous;\n\n    if st_view.is_anonymous != is_anonymous {\n        return Err(anyhow::anyhow!(\n            \"found is_anonymous={} in st_view, but {} in module when updating view `{}`\",\n            st_view.is_anonymous,\n            is_anonymous,","sourceCodeStart":1159,"sourceCodeEnd":1195,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/524b4487d949b61a07d4f39c862d1290259dfd20/crates/core/src/host/module_host.rs#L1159-L1195","documentation":"While resolving a view for refresh, the system reads the view's catalog row (st_views) and requires table_id — the backing table the view materializes into. A NULL table_id means the catalog view has no backing table, so refresh cannot proceed and resolution fails.","triggerScenarios":"Refreshing a view whose catalog row was written without a backing table (in-progress or interrupted schema change); refreshing an internal or system view that never has a backing table; catalog/module state drift around view features.","commonSituations":"Interrupted or partially failed module publishes that altered views; bugs in view catalog maintenance; early adoption of view features before stabilization.","solutions":["Re-publish the module so the view catalog is rewritten: `spacetime publish <db>`.","If reproducible and the data is disposable, delete and recreate the database (export first if needed).","Capture server logs and report to SpacetimeDB with the module code that declares the view."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await refreshViews(db);\n} catch (e) {\n  if (String(e).includes('does not have a backing table')) {\n    await spacetimePublish(dbName, modulePath); // rewrite view catalog, then retry\n    return refreshViews(db);\n  }\n  throw e;\n}","preventionTips":["Do not kill the server mid-publish; let schema changes complete.","Re-publish after any failed publish to re-converge the catalog.","Keep module sources in VCS so catalog state can always be rewritten."],"tags":["spacetimedb","views","schema","catalog","internal"],"backgroundTag":"schema-drift","analyzedSha":"524b4487d949b61a07d4f39c862d1290259dfd20","analyzedAt":"2026-08-16T23:58:54.611Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}