{"record":{"id":"c9157caed59a2f2a","repo":"clockworklabs/SpacetimeDB","slug":"there-is-already-an-http-handler-with-the-name","errorCode":null,"errorMessage":"There is already an HTTP handler with the name '${name}'","messagePattern":"There is already an HTTP handler with the name '(.+?)'","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"crates/bindings-typescript/src/server/schema.ts","lineNumber":134,"sourceCode":"  submoduleDispatchInfos: SubmoduleDispatchInfo[] = [];\n\n  constructor(getSchemaType: (ctx: SchemaInner<S>) => S) {\n    super();\n    this.schemaType = getSchemaType(this);\n  }\n\n  defineFunction(name: string) {\n    if (this.existingFunctions.has(name)) {\n      throw new TypeError(\n        `There is already a reducer, procedure, or view with the name '${name}'`\n      );\n    }\n    this.existingFunctions.add(name);\n  }\n\n  defineHttpHandler(name: string) {\n    if (this.existingHttpHandlers.has(name)) {\n      throw new TypeError(\n        `There is already an HTTP handler with the name '${name}'`\n      );\n    }\n    this.existingHttpHandlers.add(name);\n  }\n\n  resolveSchedules() {\n    if (this.schedulesResolved) {\n      return;\n    }\n    this.schedulesResolved = true;\n    // Pending schedules come from two API paths:\n    // - legacy table({ scheduled }) schedules already know their tableName and\n    //   scheduleAtCol because schema() resolves them while iterating table keys\n    // - reducer/procedure({ onSchedule }) schedules only know the table handle,\n    //   so resolve them through tableSourceNames and reject duplicate table\n    //   handle registrations because the target table name is ambiguous\n    const scheduledTables = new Map<string, string>();","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/eddf9f5014579a50d4b67630e28b6e15cad9c4af/crates/bindings-typescript/src/server/schema.ts#L116-L152","documentation":"HTTP handlers have their own namespace, tracked separately from reducer/procedure/view names in `existingHttpHandlers`. `defineHttpHandler` throws this error when a second handler export registers the same name. It fires during module build when `registerHttpHandler` (called from the handler's `[registerExport]` hook) processes your exports.","triggerScenarios":"Two `spacetimedb.httpHandler(...)` exports with the same export name; re-exporting a handler from a shared file plus defining a local one with the same name; barrel files duplicating a handler export into the entry module.","commonSituations":"Refactoring handlers into a library and re-exporting alongside an existing local handler; alias re-exports that keep the original name; two developers adding `health` handlers in different files that both get star-exported.","solutions":["Rename one of the two handlers named in the error so each HTTP handler export name is unique.","Deduplicate barrel re-exports: keep the handler exported from exactly one module path.","Note handlers and reducers may share a name across namespaces, but keeping them distinct avoids confusion; the hard rule here is handler-vs-handler only."],"exampleFix":"// before\nexport const health = spacetimedb.httpHandler(...);\nexport { health } from './handlers'; // duplicate registration\n\n// after\nexport const health = spacetimedb.httpHandler(...);\nexport { health as healthProbe } from './handlers';","handlingStrategy":"validation","validationCode":"// Keep an explicit registry of handler names in one module.\nconst handlerNames = new Set<string>();\nexport function makeHandler(name: string, fn: any) {\n  if (handlerNames.has(name)) throw new Error(`duplicate handler: ${name}`);\n  handlerNames.add(name);\n  return spacetimedb.httpHandler(/* ... */, fn);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Declare every HTTP handler in a single `handlers/` directory with one export each.","Avoid star re-exports in the entry module; enumerate handler exports explicitly.","Namespace handler names by feature (`healthReadiness`, `healthLiveness`) when defaults like `health` would collide."],"tags":["http","exports","naming","build-time","spacetimedb"],"backgroundTag":"duplicate-handler-name","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"}