clockworklabs/SpacetimeDB · error · TypeError

Submodules cannot declare environment variables

Error message

Submodules cannot declare environment variables

What it means

Submodule builds (buildSubmoduleDispatch) require the module definition to have an empty environment table. Environment variables are a top-level module concern; allowing them in submodules would create ambiguous ownership of runtime environment keys, so a TypeError is thrown when this.#ctx.moduleDef.environment is non-empty.

Solutions

  1. Move environment declarations to the top-level module definition
  2. Remove env declarations from the submodule's exports
  3. Restructure so each submodule builds a clean moduleDef with no environment entries

Example fix

// before
// submodule.ts
export const env = ctx.env('KEY', str);
// after
// main.ts (top-level module)
export const env = ctx.env('KEY', str); // submodule stays env-free
Defensive patterns

Strategy: validation

Validate before calling

if (this.#ctx.moduleDef.environment.length !== 0) {
  throw new TypeError('Refusing to build submodule: environment declarations must live at the top level');
}

Try / catch

try {
  buildSubmoduleDispatch.call(builder, exports);
} catch (e) {
  if (e instanceof TypeError && e.message.includes('environment variables')) {
    console.error('Move env declarations from the submodule to the top-level module');
  } else throw e;
}

Prevention

When it happens

Trigger: Calling buildSubmoduleDispatch (or the submodule build path it drives, e.g. buildRawModuleDefV10 with ignoreNonModuleExports) on a context whose moduleDef.environment has entries registered.

Common situations: Refactoring a monolithic module into submodules while leaving its env declarations in place; adding env vars inside a submodule export file.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

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

    });
    this.#ctx.resolveSchedules();
    return this.#ctx.rawModuleDefV10();
  }

  /**
   * @internal – called by schema() when processing a submodule namespace entry.
   * Registers the library's exports and returns both the serialized module def
   * and the runtime dispatch info needed by ModuleHooksImpl for __call_reducer__.
   */
  buildSubmoduleDispatch(exports: object): {
    rawDef: RawModuleDefV10;
    dispatch: SubmoduleDispatchInfo;
  } {
    const rawDef = this.buildRawModuleDefV10(exports, {
      ignoreNonModuleExports: true,
    });
    if (this.#ctx.moduleDef.environment.length !== 0) {
      throw new TypeError('Submodules cannot declare environment variables');
    }
    this.#ctx.resolveHttpRoutes();
    return {
      rawDef,
      dispatch: {
        namespace: '',
        reducerFns: [...this.#ctx.reducers],
        reducerDefs: [...this.#ctx.moduleDef.reducers],
        procedureFns: [...this.#ctx.procedures],
        procedureDefs: [...this.#ctx.moduleDef.procedures],
        anonViewFns: [...this.#ctx.anonViews],
        viewFns: [...this.#ctx.views],
        typespace: this.#ctx.moduleDef.typespace,
        tables: Object.values(this.#ctx.schemaType.tables).map(t => ({
          accessorName: t.accessorName,
          tableDef: t.tableDef,
        })),
        schemaTables: this.#ctx.schemaType.tables,

View on GitHub (pinned to eddf9f5014)