clockworklabs/SpacetimeDB · critical

must export schema as default export

Error message

must export schema as default export

What it means

When a JavaScript (V8) module starts, the host evaluates the module, reads its default export, and derives the hook functions (reducers, tables, lifecycle) from it. Here get_hooks returned None: the module did not yield hooks from a default export, most simply because no usable default export exists. Without it the host cannot build the module description, so instance startup fails.

Source

Thrown at crates/core/src/host/v8/mod.rs:1187

        None
    }
}

/// Performs some of the shared startup work for JS worker isolates.
///
/// NOTE(centril): in its own function due to lack of `try` blocks.
fn startup_instance_worker<'scope>(
    scope: &mut PinScope<'scope, '_>,
    program: Arc<str>,
    module_or_mcc: Either<ModuleCommon, ModuleCreationContext>,
) -> anyhow::Result<(HookFunctions<'scope>, ModuleCommon)> {
    let hook_functions = catch_exception(scope, |scope| {
        // Start-up the user's module.
        let exports_obj = eval_user_module(scope, &program)?;

        // Find the hook functions.
        let hooks =
            get_hooks(scope, exports_obj)?.ok_or_else(|| anyhow::anyhow!("must export schema as default export"))?;
        Ok(hooks)
    })?;

    // If we don't have a module, make one.
    let module_common = match module_or_mcc {
        Either::Left(module_common) => module_common,
        Either::Right(mcc) => {
            let def = extract_description(scope, &hook_functions, &mcc.replica_ctx)?;

            // Validate and create a common module from the raw definition.
            build_common_module_from_raw(mcc, def)?
        }
    };

    Ok((hook_functions, module_common))
}

/// Returns a new isolate.

View on GitHub (pinned to 524b4487d9)

Solutions

  1. Ensure the module entry default-exports the schema the bindings generate: `export default schema;`.
  2. Rebuild the bundle and inspect the dist output to confirm the default export survived bundling.
  3. Regenerate or upgrade the JS bindings so the module is built for the ABI version the host expects.
  4. Reproduce locally against the same host version before republishing.

Example fix

// before: schema built but never exported as default
export const reducers = { /* ... */ };

// after: default-export the schema object the host expects
const schema = buildSchema({ /* ... */ });
export default schema;
Defensive patterns

Strategy: validation

Validate before calling

// pre-deploy smoke check (Node): the built bundle must default-export the schema
const mod = await import('./dist/module.js');
if (mod.default === undefined) {
    throw new Error('module must default-export its schema');
}

Type guard

export function isSchemaExport(v: unknown): v is { reducers: Record<string, unknown> } {
  return typeof v === 'object' && v !== null && 'reducers' in v;
}

Prevention

When it happens

Trigger: Publishing a JS module whose bundle does not export the schema object as the default export: a missing export statement, a bundler step that dropped or renamed the default export, or a module built against bindings that do not produce the expected export shape.

Common situations: Bundler configs (minification, library mode) that rewrite or drop default exports; modules written against an old bindings generation whose export convention differs from the host's ABI expectations; partially uploaded or truncated JS bundles.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16). Data as JSON: /api/errors/1c55ab1360de07f5. Report an issue: GitHub.