clockworklabs/SpacetimeDB · error · anyhow::Error

Adding schedules is not yet implemented

Error message

Adding schedules is not yet implemented

What it means

Auto-migration plans contain an AutoMigrateStep::AddSchedule when the new module introduces a scheduled reducer. The engine handler for this step is deliberately unimplemented (anyhow::bail), so any publish whose diff adds a new schedule fails the migration instead of proceeding.

Source

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

                    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)?;
            }
            spacetimedb_schema::auto_migrate::AutoMigrateStep::AddSchedule(_) => {
                anyhow::bail!("Adding schedules is not yet implemented");
            }
            spacetimedb_schema::auto_migrate::AutoMigrateStep::RemoveSchedule(_) => {
                anyhow::bail!("Removing schedules is not yet implemented");
            }
            spacetimedb_schema::auto_migrate::AutoMigrateStep::AddRowLevelSecurity(sql_rls) => {
                log!(logger, "Adding row-level security `{sql_rls}`");
                let rls = plan.new.lookup::<RawRowLevelSecurityDefV9>(sql_rls).ok_or_else(|| {
                    anyhow::anyhow!("AddRowLevelSecurity: RLS `{sql_rls}` not found in new module def")
                })?;
                let rls = RowLevelExpr::build_row_level_expr(tx, &auth_ctx, rls)?;

                stdb.create_row_level_security(tx, rls.def)?;
            }
            spacetimedb_schema::auto_migrate::AutoMigrateStep::RemoveRowLevelSecurity(sql_rls) => {
                log!(logger, "Removing row-level security `{sql_rls}`");
                stdb.drop_row_level_security(tx, sql_rls.clone())?;
            }
            spacetimedb_schema::auto_migrate::AutoMigrateStep::AddColumns(table_name_key) => {

View on GitHub (pinned to 6dee26c6ef)

Solutions

  1. In development, delete and republish the database (spacetime delete <db> && spacetime publish <db>) so the schedule is created with the initial schema rather than migrated in.
  2. For databases that must retain data, author a manual migration (spacetime migrate) that handles the schedule change outside the auto-migrator.
  3. Defer adding the scheduled reducer until a maintenance window where recreate-and-republish (with a data export/import if needed) is acceptable.

Example fix

// before: adding a scheduled reducer to a live module triggers AddSchedule
#[spacetimedb::scheduled(reducer = every_10s)]
pub struct Tick;
spacetime publish my-db // fails

// after (dev): recreate the database so the schedule ships with the initial publish
spacetime delete my-db
spacetime publish my-db
Defensive patterns

Strategy: fallback

Validate before calling

# before publishing, check whether the diff adds a scheduled reducer:
git diff HEAD~1 -- module/ | grep -E 'spacetimedb::scheduled'
# a hit on an added (not pre-existing) schedule means auto-migrate will bail

Try / catch

match publish(&db, &module).await {
    Err(e) if e.to_string().contains("Adding schedules is not yet implemented") => {
        // dev: delete + republish; prod: schedule a manual migration window
    }
    other => other,
}

Prevention

When it happens

Trigger: Publishing a module version that declares a new scheduled reducer (#[spacetimedb::scheduled(...)]) or schedule table which did not exist in the previous version, causing AddSchedule to appear in plan.steps.

Common situations: Adding a periodic tick/cron-style reducer to an already-deployed module; introducing recurring background jobs during feature work on a database that must keep its data.

Related errors


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