clockworklabs/SpacetimeDB · error · syn::Error
scheduled table missing required columns; add these to your
Error message
scheduled table missing required columns; add these to your struct: #[primary_key] #[auto_inc] scheduled_id: u64, scheduled_at: spacetimedb::ScheduleAt,
What it means
A table marked `scheduled(...)` must contain both a `#[primary_key] #[auto_inc] scheduled_id: u64` column and a `scheduled_at: spacetimedb::ScheduleAt` column; the scheduler stores its id and firing time in them. When validation finds neither a primary-key column nor any scheduled_at column, this combined guidance is emitted at the `scheduled` argument's span, listing the exact lines to add.
Source
Thrown at crates/bindings-macro/src/table.rs:1086
}).collect();
let default_fn: TokenStream = quote! {
fn get_default_col_values() -> Vec<spacetimedb::table::ColumnDefault> {
[#(#col_defaults)*].to_vec()
}
};
let (schedule, schedule_typecheck) = args
.scheduled
.as_ref()
.map(|sched| {
let scheduled_at_column = match &sched.at {
Some(at) => Some(find_column(&columns, at)?),
None => try_find_column(&columns, "scheduled_at"),
};
// better error message when both are missing
if scheduled_at_column.is_none() && primary_key_column.is_none() {
return Err(syn::Error::new(
sched.span,
"scheduled table missing required columns; add these to your struct:\n\
#[primary_key]\n\
#[auto_inc]\n\
scheduled_id: u64,\n\
scheduled_at: spacetimedb::ScheduleAt,",
));
}
let scheduled_at_column = scheduled_at_column.ok_or_else(|| {
syn::Error::new(
sched.span,
"scheduled tables must have a `scheduled_at: spacetimedb::ScheduleAt` column. \
if the column has a name besides `scheduled_at`, you can specify it with \
`scheduled(my_reducer, at = custom_scheduled_at)`",
)
})?;
let primary_key_column = primary_key_column.ok_or_else(|| {
syn::Error::new(View on GitHub (pinned to 524b4487d9)
Solutions
- Add the two required columns exactly as the message shows: `#[primary_key] #[auto_inc] scheduled_id: u64` and `scheduled_at: spacetimedb::ScheduleAt`
- Keep the conventional names unless you also pass `at = ...` for the time column
- Re-run cargo check to confirm no further scheduled-table errors follow
Example fix
// before
#[spacetimedb::table(accessor = ticks, scheduled(run_ticks))]
struct Ticks {
payload: String,
}
// after
#[spacetimedb::table(accessor = ticks, scheduled(run_ticks))]
struct Ticks {
#[primary_key]
#[auto_inc]
scheduled_id: u64,
scheduled_at: spacetimedb::ScheduleAt,
payload: String,
} Defensive patterns
Strategy: validation
Validate before calling
# every scheduled table needs both standard columns
grep -rl 'scheduled(' src/ | xargs -r grep -L 'scheduled_id'
grep -rl 'scheduled(' src/ | xargs -r grep -L 'scheduled_at' Prevention
- Start scheduled tables from the documented template containing both required columns
- If renaming scheduled_at, immediately add `at = ...` to the scheduled(...) args
- Run cargo check right after marking a table scheduled
When it happens
Trigger: `#[spacetimedb::table(accessor = t, scheduled(reducer))]` on a struct whose fields include neither a `#[primary_key]` column nor a `scheduled_at` (or `at = ...`) column.
Common situations: Writing a first scheduled table without starting from the template; deleting or renaming both standard columns while customizing the schema.
Related errors
- scheduled tables must have a `scheduled_at: spacetimedb::Sch
- scheduled tables must have a `#[primary_key] #[auto_inc] sch
- unions not supported
- must specify table accessor, e.g. `#[spacetimedb::table(acce
- a direct index must be paired with a `#[unique] constraint
AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16).
Data as JSON: /api/errors/1a241f5252c09789.
Report an issue: GitHub.