{"record":{"id":"9f202fd4dceffe4f","repo":"clockworklabs/SpacetimeDB","slug":"could-not-find-spacetimedb-client-did-you-forget-9f202f","errorCode":null,"errorMessage":"Could not find SpacetimeDB client! Did you forget to add a `SpacetimeDBProvider`? `useTable` must be used in a Vue component tree under a `SpacetimeDBProvider` component.","messagePattern":"Could not find SpacetimeDB client! Did you forget to add a `SpacetimeDBProvider`\\? `useTable` must be used in a Vue component tree under a `SpacetimeDBProvider` component\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"crates/bindings-typescript/src/vue/useTable.ts","lineNumber":74,"sourceCode":" * @returns A tuple of [rows, isReady].\n */\nexport function useTable<TableDef extends UntypedTableDef>(\n  query: Query<TableDef>,\n  callbacks?: UseTableCallbacks<Prettify<RowType<TableDef>>>\n): [\n  DeepReadonly<Ref<readonly Prettify<RowType<TableDef>>[]>>,\n  DeepReadonly<Ref<boolean>>,\n] {\n  type Row = RowType<TableDef>;\n  const accessorName = getQueryAccessorName(query);\n  const whereExpr = getQueryWhereClause(query);\n  const querySql = toSql(query);\n\n  let conn;\n  try {\n    conn = useSpacetimeDB();\n  } catch {\n    throw new Error(\n      'Could not find SpacetimeDB client! Did you forget to add a ' +\n        '`SpacetimeDBProvider`? `useTable` must be used in a Vue component tree ' +\n        'under a `SpacetimeDBProvider` component.'\n    );\n  }\n\n  const rows = shallowRef<readonly Prettify<Row>[]>([]);\n  const isReady = ref(false);\n\n  let latestTransactionEvent: any = null;\n  let unsubscribeFromTable: (() => void) | null = null;\n  let subscriptionHandle: { unsubscribe: () => void } | null = null;\n\n  const computeFilteredRows = (): readonly Prettify<Row>[] => {\n    const connection = conn.getConnection();\n    if (!connection) return [];\n\n    const table = connection.db[accessorName];","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/6dee26c6efc2856793e12b148a59742964f5d783/crates/bindings-typescript/src/vue/useTable.ts#L56-L92","documentation":"useTable in the Vue bindings wraps useSpacetimeDB() in a try/catch and rethrows this message when inject(SPACETIMEDB_INJECTION_KEY) returned undefined. Identical root cause as the base hook — no SpacetimeDBProvider above the component, or a call outside setup() — surfaced here with useTable-specific guidance.","triggerScenarios":"Calling useTable(tables.x) from the Vue bindings in a component without a <SpacetimeDBProvider :connectionBuilder=\"...\"> ancestor; invoking the composable outside setup() context; using the provider from a different framework binding set.","commonSituations":"Multi-page apps where the provider is only around <RouterView> children but a header/footer component also reads tables; tests mounting a table component bare; refactors that moved the provider into a child route component.","solutions":["Place <SpacetimeDBProvider :connectionBuilder=\"builder\"> at the app root, above all components that read tables","Keep the useTable call inside setup() (directly or through a composable called from setup)","Verify both provider and hook are imported from the Vue bindings","In unit tests, wrap the mounted component with the provider"],"exampleFix":"// before\nexport default defineComponent({\n  setup() {\n    const [rows, isReady] = useTable(tables.player); // throws\n    return { rows, isReady };\n  },\n});\n\n// after: App.vue\n// <template>\n//   <SpacetimeDBProvider :connectionBuilder=\"builder\"><PlayerList /></SpacetimeDBProvider>\n// </template>","handlingStrategy":"try-catch","validationCode":"import { inject } from 'vue';\nimport { SPACETIMEDB_INJECTION_KEY } from './connection_state';\n\n// inside setup():\nif (inject(SPACETIMEDB_INJECTION_KEY, null) === null) {\n  // skip table wiring; provider is missing\n}","typeGuard":null,"tryCatchPattern":"// parent-level catch for components that use useTable:\n// <Suspense>\n//   <component :errorCaptured=\"(e) => { log(e); return false; }\">\n// or define an errorCaptured hook in the owning component","preventionTips":["Mount the provider at the app root, not per-route","Keep table components under the provider in the tree; add a mount-order test","Wrap table components with errorCaptured boundaries during development"],"tags":["vue","usetable","provide-inject","provider","typescript"],"backgroundTag":"missing-context-provider","analyzedSha":"6dee26c6efc2856793e12b148a59742964f5d783","analyzedAt":"2026-08-20T06:08:37.179Z","contentChangedAt":"2026-08-20T06:08:37.179Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}