{"record":{"id":"36512f6c8c0fdd61","repo":"clockworklabs/SpacetimeDB","slug":"adding-schedules-is-not-yet-implemented","errorCode":null,"errorMessage":"Adding schedules is not yet implemented","messagePattern":"Adding schedules is not yet implemented","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/engine/src/update.rs","lineNumber":594,"sourceCode":"                    if view_def.is_public {\n                        TableAccess::Public\n                    } else {\n                        TableAccess::Private\n                    }\n                };\n                stdb.alter_table_access(tx, &table_name, access.into())?;\n            }\n            spacetimedb_schema::auto_migrate::AutoMigrateStep::ChangePrimaryKey(table_name_key) => {\n                let (namespace, local) = table_name_key;\n                let table_name = joined(namespace, local);\n                let (_owning_def, table_def) = plan.new.find_table(table_name_key).ok_or_else(|| {\n                    anyhow::anyhow!(\"ChangePrimaryKey: table `{table_name}` not found in new module def\")\n                })?;\n                log!(logger, \"Changing primary key for table `{table_name}`\");\n                stdb.alter_table_primary_key(tx, &table_name, table_def.primary_key)?;\n            }\n            spacetimedb_schema::auto_migrate::AutoMigrateStep::AddSchedule(_) => {\n                anyhow::bail!(\"Adding schedules is not yet implemented\");\n            }\n            spacetimedb_schema::auto_migrate::AutoMigrateStep::RemoveSchedule(_) => {\n                anyhow::bail!(\"Removing schedules is not yet implemented\");\n            }\n            spacetimedb_schema::auto_migrate::AutoMigrateStep::AddRowLevelSecurity(sql_rls) => {\n                log!(logger, \"Adding row-level security `{sql_rls}`\");\n                let rls = plan.new.lookup::<RawRowLevelSecurityDefV9>(sql_rls).ok_or_else(|| {\n                    anyhow::anyhow!(\"AddRowLevelSecurity: RLS `{sql_rls}` not found in new module def\")\n                })?;\n                let rls = RowLevelExpr::build_row_level_expr(tx, &auth_ctx, rls)?;\n\n                stdb.create_row_level_security(tx, rls.def)?;\n            }\n            spacetimedb_schema::auto_migrate::AutoMigrateStep::RemoveRowLevelSecurity(sql_rls) => {\n                log!(logger, \"Removing row-level security `{sql_rls}`\");\n                stdb.drop_row_level_security(tx, sql_rls.clone())?;\n            }\n            spacetimedb_schema::auto_migrate::AutoMigrateStep::AddColumns(table_name_key) => {","sourceCodeStart":576,"sourceCodeEnd":612,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/6dee26c6efc2856793e12b148a59742964f5d783/crates/engine/src/update.rs#L576-L612","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","For databases that must retain data, author a manual migration (spacetime migrate) that handles the schedule change outside the auto-migrator.","Defer adding the scheduled reducer until a maintenance window where recreate-and-republish (with a data export/import if needed) is acceptable."],"exampleFix":"// before: adding a scheduled reducer to a live module triggers AddSchedule\n#[spacetimedb::scheduled(reducer = every_10s)]\npub struct Tick;\nspacetime publish my-db // fails\n\n// after (dev): recreate the database so the schedule ships with the initial publish\nspacetime delete my-db\nspacetime publish my-db","handlingStrategy":"fallback","validationCode":"# before publishing, check whether the diff adds a scheduled reducer:\ngit diff HEAD~1 -- module/ | grep -E 'spacetimedb::scheduled'\n# a hit on an added (not pre-existing) schedule means auto-migrate will bail","typeGuard":null,"tryCatchPattern":"match publish(&db, &module).await {\n    Err(e) if e.to_string().contains(\"Adding schedules is not yet implemented\") => {\n        // dev: delete + republish; prod: schedule a manual migration window\n    }\n    other => other,\n}","preventionTips":["Introduce all scheduled reducers in the initial publish of a database, not in later updates.","Treat schedule additions/removals as breaking changes requiring recreate or manual migration.","Review schema diffs for #[spacetimedb::scheduled] before every publish to a live database."],"tags":["migration","schedules","scheduled-reducers","not-implemented","auto-migrate"],"backgroundTag":"unsupported-migration-step","analyzedSha":"6dee26c6efc2856793e12b148a59742964f5d783","analyzedAt":"2026-08-20T06:08:37.179Z","contentChangedAt":"2026-08-20T06:08:37.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}