clockworklabs/SpacetimeDB · critical
default export is not a Schema object
Error message
default export is not a Schema object
What it means
The JS module's default export was found and is neither null nor undefined, but v2::get_hooks_from_default_export could not interpret it as a Schema object — it does not carry the structure ABI-v2 bindings attach to exported schemas. The host therefore cannot extract reducer/table/lifecycle hooks and startup fails. A default export exists, but it is the wrong kind of value.
Source
Thrown at crates/core/src/host/v8/syscall/mod.rs:145
) -> Result<Option<HookFunctions<'scope>>, ErrorOrException<ExceptionThrown>> {
// We only set RECV_SLOT_INDEX in set_registered_hooks, which is only called in
// the v2 code path. Set it to undefined ahead of time so it's not a garbage value.
scope
.get_current_context()
.set_embedder_data(hooks::RECV_SLOT_INDEX, v8::undefined(scope).into());
if let Some(hooks) = get_registered_hooks(scope) {
return Ok(Some(hooks));
}
let default = super::str_from_ident!(default).string(scope);
let default_export = exports_obj
.get(scope, default.into())
.ok_or_else(exception_already_thrown)?;
if default_export.is_null_or_undefined() {
return Ok(None);
}
let hooks = v2::get_hooks_from_default_export(scope, default_export, exports_obj)?
.ok_or_else(|| anyhow::anyhow!("default export is not a Schema object"))?;
Ok(Some(hooks))
}
/// Process the thrown exception value into an `ExecutionError`.
pub(super) fn process_thrown_exception(
scope: &mut PinScope<'_, '_>,
hooks: &HookFunctions<'_>,
exc: Local<'_, v8::Value>,
) -> ExcResult<Option<ExecutionError>> {
match hooks.abi {
AbiVersion::V1 => Ok(None),
AbiVersion::V2 => v2::process_thrown_exception(scope, hooks, exc),
}
}
View on GitHub (pinned to 524b4487d9)
Solutions
- Default-export exactly the schema value produced by the generated bindings.
- Upgrade or regenerate the JS bindings so the exported object matches the host's ABI v2 expectations.
- Add a pre-deploy smoke check that imports the built bundle and validates the default export.
- Diff against a freshly scaffolded module to see the expected export shape.
Example fix
// before: default export is not the schema object
export default { reducers, tables };
// after: default-export the schema the bindings generate
const schema = buildSchema({ reducers, tables });
export default schema; Defensive patterns
Strategy: type-guard
Validate before calling
// pre-deploy check: the default export must look like the generated Schema
const mod = await import('./dist/module.js');
if (!isSchemaObject(mod.default)) {
throw new Error('default export is not a Schema object');
} Type guard
export function isSchemaObject(v: unknown): v is { reducers: object; tables: object } {
return typeof v === 'object' && v !== null && 'reducers' in v && 'tables' in v;
} Prevention
- Export exactly the value the generated bindings produce as default.
- Do not hand-roll the default export.
- Diff a failing module against a fresh scaffold to spot export-shape drift.
When it happens
Trigger: Default-exporting a plain object, class, or function instead of the generated schema: `export default {}`, `export default MyComponent`, or a schema value produced by a different (older/newer) bindings generation than the host's ABI v2 expects.
Common situations: Hand-written entry points exporting the wrong symbol; modules built with bindings whose Schema shape predates ABI v2; refactors where an intermediate builder value is exported instead of the finished schema.
Related errors
- must export schema as default export
- Math.random is not available in SpacetimeDB modules. Use ctx
- The encoding label provided is invalid
- Option 'ignoreBOM' not supported
- Option 'stream' not supported
AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16).
Data as JSON: /api/errors/b897b646667d1b64.
Report an issue: GitHub.