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
- Move environment declarations to the top-level module definition
- Remove env declarations from the submodule's exports
- 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
- Keep all ctx.env calls in the top-level module file
- Add a build-time check that submodule files export no env vars
- Document the env-ownership rule for submodule authors
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
- Environment ' ' cannot use an enum payload
- Environment ' ' enum cases must have names
- Environment ' ' literal is too long
- Environment ' ' must be a string or simple enum
- Environment ' ' needs a nonempty literal union
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)