clockworklabs/SpacetimeDB · error · TypeError
Table defines a schedule, but it does not have a ScheduleAt…
Error message
Table ${tableName} defines a schedule, but it does not have a ScheduleAt column. What it means
A scheduled table must declare which column holds the scheduled timestamp. Resolution order is `knownScheduleAtCol` (legacy schedule API) then `table.scheduleAtCol`, which is set when the row type contains a `t.scheduleAt()` column. If neither exists, the build fails with `Table ${tableName} defines a schedule, but it does not have a ScheduleAt column.`
Solutions
- Add `scheduledAt: t.scheduleAt()` to the scheduled table's row type.
- Do not substitute other timestamp builders — only `t.scheduleAt()` marks the column for scheduling.
- If you use the legacy `table({... schedule ...})` API, set `scheduleAtCol` to the column's index explicitly.
Example fix
// before
const scheduledMessages = table({}, {
id: t.u64().primaryKey().autoInc(),
text: t.string(), // no scheduleAt column
});
// after
const scheduledMessages = table({}, {
id: t.u64().primaryKey().autoInc(),
scheduledAt: t.scheduleAt(),
text: t.string(),
}); Defensive patterns
Strategy: validation
Validate before calling
// For dynamically assembled rows: require a scheduleAt builder on scheduled tables.
function assertScheduleRow(row: Record<string, any>) {
const hasScheduleAt = Object.values(row).some(c => c?.__scheduleAt === true);
if (!hasScheduleAt) throw new Error('scheduled table row is missing t.scheduleAt()');
} Type guard
type HasScheduleAt<R> = R extends { scheduledAt: infer C } ? (C extends { __scheduleAt: true } ? true : false) : false; Prevention
- Copy the canonical scheduled-row template: `id: t.u64().primaryKey().autoInc(), scheduledAt: t.scheduleAt()`.
- Only `t.scheduleAt()` marks the column; other timestamp builders do not.
- Keep a typecheck step (`tsc --noEmit`) in CI to catch missing builders before publish.
When it happens
Trigger: Building a table for a scheduled reducer without `scheduledAt: t.scheduleAt()` in its row; using a plain `t.timestampNtz()`/`t.string()` column instead of the dedicated `scheduleAt()` builder; constructing the table dynamically so `scheduleAtCol` is never recorded.
Common situations: Copying a normal table row into a scheduled context and swapping the primary key but forgetting the schedule column; assuming any timestamp column qualifies; upgrading from a legacy schedule API that inferred the column differently.
Related errors
- Schedule target table is not part of this schema.
- Schedule target table is registered more than once in this…
- Table defines multiple schedules: and . A schedule table…
- invalid sequence type
- multiple schemas are not supported
AI-assisted analysis of clockworklabs/SpacetimeDB@eddf9f5014 (2026-08-20).
Data as JSON: /api/errors/1269a181f670a7c5.
Report an issue: GitHub.
Appendix: source
Thrown at crates/bindings-typescript/src/server/schema.ts:178
let tableName = knownTableName;
if (tableName === undefined) {
const tableNames = this.tableSourceNames.get(table);
if (tableNames !== undefined && tableNames.length > 1) {
throw new TypeError(
'Schedule target table is registered more than once in this schema. Use a distinct table handle for each scheduled table.'
);
}
tableName = tableNames?.[0];
}
if (tableName === undefined) {
throw new TypeError(
'Schedule target table is not part of this schema.'
);
}
const scheduleAtCol = knownScheduleAtCol ?? table.scheduleAtCol;
if (scheduleAtCol === undefined) {
throw new TypeError(
`Table ${tableName} defines a schedule, but it does not have a ScheduleAt column.`
);
}
const functionName =
knownFunctionName ??
(reducer === undefined
? undefined
: this.functionExports.get(reducer()));
if (functionName === undefined) {
const msg = `Table ${tableName} defines a schedule, but it seems like the associated function was not exported.`;
throw new TypeError(msg);
}
const existingFunctionName = scheduledTables.get(tableName);
if (existingFunctionName !== undefined) {
throw new TypeError(
`Table ${tableName} defines multiple schedules: ${existingFunctionName} and ${functionName}. A schedule table can only be used by one reducer or procedure.`
);View on GitHub (pinned to eddf9f5014)