clockworklabs/SpacetimeDB · error · TypeError
There is already a reducer, procedure, or view with the name
Error message
There is already a reducer, procedure, or view with the name '${name}' What it means
SchemaInner.defineFunction guards a single shared namespace: reducers, procedures, and views may not share a name within a module (submodules are flattened into one dispatch table, so their function names also collide). Registering a second function with an existing name throws a TypeError during schema construction, before the module can build or deploy.
Source
Thrown at crates/bindings-typescript/src/server/schema.ts:124
* Maps reducer/procedure export objects to their source names.
* Used for resolving scheduled table targets.
*/
functionExports: Map<UntypedScheduledFunctionExport, string> = new Map();
tableSourceNames: Map<UntypedTableSchema, string[]> = new Map();
httpHandlerExports: Map<HttpHandlerExport<UntypedSchemaDef>, string> =
new Map();
pendingSchedules: PendingSchedule[] = [];
pendingHttpRoutes: PendingHttpRoute[] = [];
submoduleDispatchInfos: SubmoduleDispatchInfo[] = [];
constructor(getSchemaType: (ctx: SchemaInner<S>) => S) {
super();
this.schemaType = getSchemaType(this);
}
defineFunction(name: string) {
if (this.existingFunctions.has(name)) {
throw new TypeError(
`There is already a reducer, procedure, or view with the name '${name}'`
);
}
this.existingFunctions.add(name);
}
defineHttpHandler(name: string) {
if (this.existingHttpHandlers.has(name)) {
throw new TypeError(
`There is already an HTTP handler with the name '${name}'`
);
}
this.existingHttpHandlers.add(name);
}
resolveSchedules() {
if (this.schedulesResolved) {
return;View on GitHub (pinned to 524b4487d9)
Solutions
- Rename one of the colliding functions so every reducer/procedure/view name is unique module-wide
- If submodules collide, rename inside one submodule or lean on its namespace/name prefix so flattened names differ
- Search the whole module (including all submodules) for the name in the error message to locate both definitions
Example fix
// before
function leaderboard() {} // reducer
function leaderboard() {} // view -> TypeError at schema build
// after
function leaderboard() {} // reducer
function leaderboardView() {} // view Defensive patterns
Strategy: validation
Validate before calling
// during module build, guard the shared reducer/procedure/view namespace:
const seen = new Set<string>();
function checkFunctionName(name: string): void {
if (seen.has(name)) throw new Error(`duplicate function name: ${name}`);
seen.add(name);
}
// call for every reducer, procedure, and view (including submodules) Prevention
- Treat reducer, procedure, and view names as one namespace when naming functions
- Avoid generic names (init, update, tick) in submodules that get flattened together
- Add a naming lint or startup check that scans all exported functions for duplicates
When it happens
Trigger: Two reducers with the same name; a view named the same as a reducer or procedure (e.g. both called `leaderboard`); two submodules that each export a function with a common name like `init` or `update` and get flattened together.
Common situations: Copy-pasted reducers renamed at call sites but not in their definitions; merging submodules with overlapping generic names; refactoring a view into a procedure while keeping the old view.
Related errors
- cannot serialize refs without a typespace
- cannot deserialize refs without a typespace
- Missing type name for ${typeBuilder.constructor.name ?? 'Typ
- Only btree indexes are supported in TableCacheImpl
- HTTP handler '${exportName}' was exported more than once
AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16).
Data as JSON: /api/errors/d83690c7dd80c42f.
Report an issue: GitHub.