{"record":{"id":"1269a181f670a7c5","repo":"clockworklabs/SpacetimeDB","slug":"table-tablename-defines-a-schedule-but-it-does","errorCode":null,"errorMessage":"Table ${tableName} defines a schedule, but it does not have a ScheduleAt column.","messagePattern":"Table (.+?) defines a schedule, but it does not have a ScheduleAt column\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"crates/bindings-typescript/src/server/schema.ts","lineNumber":178,"sourceCode":"      let tableName = knownTableName;\n      if (tableName === undefined) {\n        const tableNames = this.tableSourceNames.get(table);\n        if (tableNames !== undefined && tableNames.length > 1) {\n          throw new TypeError(\n            'Schedule target table is registered more than once in this schema. Use a distinct table handle for each scheduled table.'\n          );\n        }\n        tableName = tableNames?.[0];\n      }\n      if (tableName === undefined) {\n        throw new TypeError(\n          'Schedule target table is not part of this schema.'\n        );\n      }\n\n      const scheduleAtCol = knownScheduleAtCol ?? table.scheduleAtCol;\n      if (scheduleAtCol === undefined) {\n        throw new TypeError(\n          `Table ${tableName} defines a schedule, but it does not have a ScheduleAt column.`\n        );\n      }\n\n      const functionName =\n        knownFunctionName ??\n        (reducer === undefined\n          ? undefined\n          : this.functionExports.get(reducer()));\n      if (functionName === undefined) {\n        const msg = `Table ${tableName} defines a schedule, but it seems like the associated function was not exported.`;\n        throw new TypeError(msg);\n      }\n      const existingFunctionName = scheduledTables.get(tableName);\n      if (existingFunctionName !== undefined) {\n        throw new TypeError(\n          `Table ${tableName} defines multiple schedules: ${existingFunctionName} and ${functionName}. A schedule table can only be used by one reducer or procedure.`\n        );","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/eddf9f5014579a50d4b67630e28b6e15cad9c4af/crates/bindings-typescript/src/server/schema.ts#L160-L196","documentation":"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.`","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nconst scheduledMessages = table({}, {\n  id: t.u64().primaryKey().autoInc(),\n  text: t.string(), // no scheduleAt column\n});\n\n// after\nconst scheduledMessages = table({}, {\n  id: t.u64().primaryKey().autoInc(),\n  scheduledAt: t.scheduleAt(),\n  text: t.string(),\n});","handlingStrategy":"validation","validationCode":"// For dynamically assembled rows: require a scheduleAt builder on scheduled tables.\nfunction assertScheduleRow(row: Record<string, any>) {\n  const hasScheduleAt = Object.values(row).some(c => c?.__scheduleAt === true);\n  if (!hasScheduleAt) throw new Error('scheduled table row is missing t.scheduleAt()');\n}","typeGuard":"type HasScheduleAt<R> = R extends { scheduledAt: infer C } ? (C extends { __scheduleAt: true } ? true : false) : false;","tryCatchPattern":null,"preventionTips":["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."],"tags":["scheduling","schema","tables","build-time","spacetimedb"],"backgroundTag":"missing-scheduleat-column","analyzedSha":"eddf9f5014579a50d4b67630e28b6e15cad9c4af","analyzedAt":"2026-08-20T06:08:37.179Z","contentChangedAt":"2026-08-20T06:08:37.179Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}