clockworklabs/SpacetimeDB · error · Error
SpacetimeDBQueryClient can only handle spacetimedb queries…
Error message
SpacetimeDBQueryClient can only handle spacetimedb queries, got: ${prefix} What it means
SpacetimeDBQueryClient implements TanStack Query's QueryFunction contract and validates that each incoming queryKey is the triple ['spacetimedb', accessorName, querySql] produced by the spacetimeDBQuery() helper. Any key whose first element is not the literal 'spacetimedb' is rejected, because the client's subscription and cache-hydration logic only understands keys it created (it also looks the SQL string up in an internal queryRegistry filled by spacetimeDBQuery).
Solutions
- Build query options only with spacetimeDBQuery(tables.x) or spacetimeDBQuery(tables.x.where(...)), never by hand
- Do not install this queryFn as the QueryClient's defaultQueryFn if the client also serves other queries — pass it per query
- Never override or reorder the queryKey from spacetimeDBQuery(); spread the whole options object into useQuery
- If you must construct keys manually, use the exact shape ['spacetimedb', accessorName, sql] and make sure spacetimeDBQuery() ran for that query so it is in the registry
Example fix
// before
const { data } = useQuery({
queryKey: ['players', userId], // prefix is not 'spacetimedb'
queryFn: stdbQueryClient.queryFn,
});
// after
import { spacetimeDBQuery } from '@clockworklabs/spacetime-db-tanstack';
const { data } = useQuery({
...spacetimeDBQuery(tables.player), // queryKey: ['spacetimedb', 'player', sql]
queryFn: stdbQueryClient.queryFn,
}); Defensive patterns
Strategy: validation
Validate before calling
function isSpacetimeDBKey(key: readonly unknown[]): boolean {
return key[0] === 'spacetimedb';
}
// before wiring the queryFn:
if (isSpacetimeDBKey(options.queryKey)) {
// safe for SpacetimeDBQueryClient.queryFn
} Type guard
function isSpacetimeDBKey(key: readonly unknown[]): key is readonly ['spacetimedb', string, string] {
return (
Array.isArray(key) &&
key.length === 3 &&
key[0] === 'spacetimedb' &&
typeof key[1] === 'string' &&
typeof key[2] === 'string'
);
} Try / catch
// better than catching: never hand-build keys — always spread spacetimeDBQuery(...)
Prevention
- Only use spacetimeDBQuery() to produce query options
- Do not set this queryFn as a QueryClient-wide default alongside REST queries
- Code-review any custom queryKey that interacts with this client
When it happens
Trigger: Setting SpacetimeDBQueryClient.queryFn as the default queryFn of a QueryClient that also runs non-SpacetimeDB queries; calling queryClient.fetchQuery/prefetchQuery with a hand-built key; overriding or reordering the queryKey returned by spacetimeDBQuery(); spreading the options object but replacing queryKey.
Common situations: Hybrid apps mixing REST and SpacetimeDB queries on one QueryClient; refactors that rename or namespace query keys; copying examples that set defaultOptions.queries.queryFn globally.
Related errors
- Brotli compression is not supported by the runtime. Please…
- Cannot nest router at
- Could not find SpacetimeDB client! Did you forget to add a…
- Could not find SpacetimeDB client! Did you forget to call…
- 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/a8abef0b9156d41b.
Report an issue: GitHub.
Appendix: source
Thrown at crates/bindings-typescript/src/tanstack/SpacetimeDBQueryClient.ts:135
}
}
});
}
queryFn: QueryFunction<any[], QueryKey> = async ({
queryKey,
}: {
queryKey: QueryKey;
}) => {
const keyStr = JSON.stringify(queryKey);
const [prefix, accessorName, querySql] = queryKey as [
string,
string,
string,
];
if (prefix !== 'spacetimedb') {
throw new Error(
`SpacetimeDBQueryClient can only handle spacetimedb queries, got: ${prefix}`
);
}
const registered = queryRegistry.get(querySql);
const whereExpr = registered?.whereExpr;
const existingSub = this.subscriptions.get(keyStr);
if (existingSub?.applied) {
return this.getTableData(existingSub.tableInstance, whereExpr);
}
// queue query if connection not ready yet
if (!this.connection) {
return new Promise<any[]>(resolve => {
const pending = this.pendingQueries.get(keyStr) || [];
pending.push({ resolve, querySql, whereExpr });
this.pendingQueries.set(keyStr, pending);View on GitHub (pinned to 6dee26c6ef)