clockworklabs/SpacetimeDB · error · TypeError

multiple schemas are not supported

Error message

multiple schemas are not supported

What it means

Every export object created by a schema (reducers, procedures, views, HTTP handlers) carries a hidden `[exportContext]` referring to the SchemaInner it was built from. Before registering an export, `checkExportContext` verifies the export's context is the same schema doing the registration; mixing exports from two different `schema()` instances throws 'multiple schemas are not supported'. A module must be built against exactly one schema instance.

Solutions

  1. Create ALL exports from the single schema instance whose entry object you pass to `schema()` — import that instance everywhere instead of constructing a second one.
  2. If a submodule library defines tables/reducers, follow the submodule pattern: import the library as a namespace (`import * as lib from 'lib'`) and pass the namespace object as a schema entry, so the library's schema is nested rather than mixed.
  3. After test/HMR reloads, rebuild exports fresh alongside the fresh schema instead of reusing cached export objects.

Example fix

// before
// lib.ts
export const libSchema = schema({ t1 });
export const libReducer = libSchema.reducer(...);
// app.ts — different schema instance registering libReducer
export default schema({ t2, libReducer }); // TypeError: multiple schemas are not supported

// after — nest the library as a submodule namespace
import * as lib from './lib';
export default schema({ t2, lib });
Defensive patterns

Strategy: type-guard

Validate before calling

// Create all exports from one shared schema instance.
// schemaInstance.ts
import { schema } from '...';
export const appSchema = schema({ /* tables */ });
// everywhere else: import { appSchema } from './schemaInstance';

Type guard

// If you can compare against the schema instance:
function belongsToSchema(exp: unknown, schemaInstance: unknown): boolean {
  return typeof exp === 'function' || typeof exp === 'object'; // real check needs the hidden [exportContext]; proxy it by tracking creators
}
// Practical guard: maintain a Set of exports created via appSchema.* and check membership.

Prevention

When it happens

Trigger: Calling `schema({...})` twice (e.g. in two files) and exporting functions created from instance A while instance B registers the module; a library submodule creating its exports against its own `schema()` call and the app re-exporting them; HMR/test setups that rebuild the schema but reuse stale export objects.

Common situations: Shared 'base' module that defines `export const baseSchema = schema({...})` plus its reducers, later imported into an app with its own `schema()`; accidentally importing the schema from a package's entry and also constructing one locally; hot-reload keeping old module objects alive.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@eddf9f5014 (2026-08-20). Data as JSON: /api/errors/608354caffe42ca9. Report an issue: GitHub.

Appendix: source

Thrown at crates/bindings-typescript/src/server/schema.ts:729

export const exportContext = Symbol('SpacetimeDB.exportContext');

export interface ModuleExport {
  [registerExport](ctx: SchemaInner, exportName: string): void;
  [exportContext]?: SchemaInner;
}

function isModuleExport(x: unknown): x is ModuleExport {
  return (
    (typeof x === 'function' || typeof x === 'object') &&
    x !== null &&
    registerExport in x
  );
}

/** Verify that the ModuleContext that `exp` comes from is the same as `schema` */
function checkExportContext(exp: ModuleExport, schema: SchemaInner) {
  if (exp[exportContext] != null && exp[exportContext] !== schema) {
    throw new TypeError('multiple schemas are not supported');
  }
}

/**
 * Extracts the inferred schema type from a Schema instance
 */
export type InferSchema<SchemaDef extends Schema<any>> =
  SchemaDef extends Schema<infer S> ? S : never;

/**
 * Creates a schema from table definitions
 * @param handles - Array of table handles created by table() function
 * @returns ColumnBuilder representing the complete database schema
 * @example
 * ```ts
 * const spacetimedb = schema({
 *   user: table({}, userType),
 *   post: table({}, postType)

View on GitHub (pinned to eddf9f5014)