clockworklabs/SpacetimeDB · error

ChangeAccess: `{table_name}` not found as a table or view in

Error message

ChangeAccess: `{table_name}` not found as a table or view in new module def

What it means

Changing a table's or view's access (public/private): the engine looks the entity up first as a table (plan.new.find_table) and then as a view (plan.new.find_view); neither resolves in the new module def. The access-change step references an entity that exists neither as table nor as view in the new defs. The publish aborts.

Source

Thrown at crates/engine/src/update.rs:574

                let table_name = joined(namespace, local);
                let (owning_def, table_def) = plan.new.find_table(table_name_key).ok_or_else(|| {
                    anyhow::anyhow!("ReschemaEventTable: table `{table_name}` not found in new module def")
                })?;
                let table_id = stdb.table_id_from_name_mut(tx, &table_name).unwrap().unwrap();
                let column_schemas = column_schemas_from_defs(owning_def, &table_def.columns, table_id);

                log!(logger, "Changing schema of event table `{}`", table_name);

                stdb.alter_event_table_row_type(tx, table_id, column_schemas)?;
            }
            spacetimedb_schema::auto_migrate::AutoMigrateStep::ChangeAccess(table_name_key) => {
                let (namespace, local) = table_name_key;
                let table_name = joined(namespace, local);
                let access = if let Some((_owning_def, table_def)) = plan.new.find_table(table_name_key) {
                    table_def.table_access
                } else {
                    let (_owning_def, view_def) = plan.new.find_view(table_name_key).ok_or_else(|| {
                        anyhow::anyhow!("ChangeAccess: `{table_name}` not found as a table or view in new module def")
                    })?;
                    if view_def.is_public {
                        TableAccess::Public
                    } else {
                        TableAccess::Private
                    }
                };
                stdb.alter_table_access(tx, &table_name, access.into())?;
            }
            spacetimedb_schema::auto_migrate::AutoMigrateStep::ChangePrimaryKey(table_name_key) => {
                let (namespace, local) = table_name_key;
                let table_name = joined(namespace, local);
                let (_owning_def, table_def) = plan.new.find_table(table_name_key).ok_or_else(|| {
                    anyhow::anyhow!("ChangePrimaryKey: table `{table_name}` not found in new module def")
                })?;
                log!(logger, "Changing primary key for table `{table_name}`");
                stdb.alter_table_primary_key(tx, &table_name, table_def.primary_key)?;
            }

View on GitHub (pinned to 6dee26c6ef)

Solutions

  1. Clean-rebuild and republish.
  2. Change access in its own publish with the entity's name, kind, and location untouched.
  3. Do the rename/move or table-to-view conversion in a separate publish.
  4. Pin names with #[table(name = "...")] to keep keys stable.
  5. Dev: spacetime publish --delete-data <db>.
  6. Report persistent cases with the entity declarations.

Example fix

// before: make public + rename in one publish
#[spacetimedb::table(name = "members", public)] // was "players", private
pub struct Member {}

// after: two publishes
// 1) #[spacetimedb::table(name = "players", public)]
// 2) rename to "members" afterwards
Defensive patterns

Strategy: validation

Validate before calling

use spacetimedb_schema::auto_migrate::AutoMigrateStep;
for step in &plan.steps {
    if let AutoMigrateStep::ChangeAccess(key) = step {
        if plan.new.find_table(key).is_none() && plan.new.find_view(key).is_none() {
            anyhow::bail!("ChangeAccess step references {:?} that is neither table nor view in new def", key);
        }
    }
}

Type guard

fn entity_in_new_def(plan: &AutoMigratePlan, key: (&str, &str)) -> bool {
    plan.new.find_table(key).is_some() || plan.new.find_view(key).is_some()
}

Try / catch

match update_database(&stdb, tx, &plan, ...).await {
    Err(e) if e.to_string().contains("ChangeAccess") => {
        // Split: toggle access with the entity unchanged; rename/convert in a later publish.
    }
    result => result?,
}

Prevention

When it happens

Trigger: Toggling public on a table or view while renaming it, deleting it, or converting it between table and view in the same publish, so the (namespace, local) key matches nothing in the new def.

Common situations: Making an entity public during a rename refactor; switching an entity from a stored table to a computed view (or vice versa) in one publish.

Related errors


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