clockworklabs/SpacetimeDB · error · Error
Could not find SpacetimeDB client! Did you forget to call…
Error message
Could not find SpacetimeDB client! Did you forget to call `createSpacetimeDBProvider`? `useTable` must be used in a Svelte component tree under a component that called `createSpacetimeDBProvider`.
What it means
useTable in the Svelte bindings wraps useSpacetimeDB() in a try/catch and rethrows this message when the context store is missing. It fires under exactly the same conditions as the base hook: no ancestor called createSpacetimeDBProvider during component initialization, so there is no connection store to subscribe with.
Solutions
- Create the provider once in the root layout component: `const db = createSpacetimeDBProvider(builder)`
- Move any component calling useTable under that layout/component in the tree
- Ensure no `await` separates component init from the createSpacetimeDBProvider call
- For isolated tests, create the provider in the test harness component that wraps the component under test
Example fix
<!-- before -->
<script lang="ts">
const [rows, isReady] = useTable(tables.player); // throws
</script>
<!-- after: root +layout.svelte -->
<script lang="ts">
import { createSpacetimeDBProvider } from '@clockworklabs/spacetime-db-svelte';
const db = createSpacetimeDBProvider(builder);
</script>
<slot />
<!-- any descendant may now call useTable safely --> Defensive patterns
Strategy: validation
Validate before calling
import { hasContext } from 'svelte';
import { SPACETIMEDB_CONTEXT_KEY } from './connection_state';
export const canUseTable = () => hasContext(SPACETIMEDB_CONTEXT_KEY); Try / catch
// In Svelte 5, wrap risky children in an error boundary snippet; otherwise guard with canUseTable() before calling useTable
Prevention
- Create the provider once in +layout.svelte covering every route that reads tables
- Add a canUseTable() assertion helper used by all table components during development
- Keep table-reading components below the layout that owns the provider
When it happens
Trigger: Calling useTable(tables.x) or useTable(tables.x.where(...)) in a Svelte component without an ancestor that called createSpacetimeDBProvider(builder); also when the hook runs outside synchronous component init (module scope, onMount, after an await), where getContext cannot find the key.
Common situations: Table-reading components used across routes while the provider exists on only one; refactor moved the provider call deeper into the tree; SvelteKit prerender or HMR paths mounting consumers without the layout that owns the provider.
Related errors
- useSpacetimeDB must be used within a component that called…
- Could not find SpacetimeDB client! Did you forget to add a…
- Could not find SpacetimeDB client! Did you forget to add a…
- useSpacetimeDB must be used within a SpacetimeDBProvider…
- Could not find SpacetimeDB client! Did you forget to add a…
AI-assisted analysis of clockworklabs/SpacetimeDB@6dee26c6ef (2026-08-20).
Data as JSON: /api/errors/8ee62608ad523a0c.
Report an issue: GitHub.
Appendix: source
Thrown at crates/bindings-typescript/src/svelte/useTable.ts:63
*
* @param query - A query builder expression (table reference or filtered query).
* @param callbacks - Optional callbacks for row insert, delete, and update events.
* @returns A tuple of [rows, isReady].
*/
export function useTable<TableDef extends UntypedTableDef>(
query: Query<TableDef>,
callbacks?: UseTableCallbacks<Prettify<RowType<TableDef>>>
): [Readable<readonly Prettify<RowType<TableDef>>[]>, Readable<boolean>] {
type Row = RowType<TableDef>;
const accessorName = getQueryAccessorName(query);
const whereExpr = getQueryWhereClause(query);
const querySql = toSql(query);
let connectionStore;
try {
connectionStore = useSpacetimeDB();
} catch {
throw new Error(
'Could not find SpacetimeDB client! Did you forget to call ' +
'`createSpacetimeDBProvider`? `useTable` must be used in a Svelte component tree ' +
'under a component that called `createSpacetimeDBProvider`.'
);
}
const rows = writable<readonly Prettify<Row>[]>([]);
const isReady = writable(false);
let latestTransactionEvent: any = null;
let unsubscribeFromTable: (() => void) | null = null;
let subscriptionHandle: { unsubscribe: () => void } | null = null;
const computeFilteredRows = (): readonly Prettify<Row>[] => {
const state = get(connectionStore);
const connection = state.getConnection();
if (!connection) return [];
View on GitHub (pinned to 6dee26c6ef)