{"record":{"id":"620774a29a07f3ad","repo":"moeru-ai/airi","slug":"pinia-synchronization-is-not-installed-call-app-use-synced","errorCode":null,"errorMessage":"Pinia synchronization is not installed. Call app.use(synced.vue) first.","messagePattern":"Pinia synchronization is not installed\\. Call app\\.use\\(synced\\.vue\\) first\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/stage-ui/src/libs/pinia/synced-context.ts","lineNumber":13,"sourceCode":"import type { SyncedPiniaRuntime } from 'pinia-plugin-synced'\nimport type { InjectionKey } from 'vue'\n\nimport { inject } from 'vue'\n\n/** Shares the installed runtime without importing its transport and election implementation. */\nexport const injectKeyPiniaSynced: InjectionKey<SyncedPiniaRuntime> = Symbol('stage-synced-pinia-runtime')\n\n/** Returns the synchronization runtime installed by the application's setupSynced plugin. */\nexport function usePiniaSynced(): SyncedPiniaRuntime {\n  const runtime = inject(injectKeyPiniaSynced)\n  if (!runtime)\n    throw new Error('Pinia synchronization is not installed. Call app.use(synced.vue) first.')\n  return runtime\n}\n","sourceCodeStart":1,"sourceCodeEnd":16,"githubUrl":"https://github.com/moeru-ai/airi/blob/438a067dde47aa0bdb46c2323d1fe293dc805218/packages/stage-ui/src/libs/pinia/synced-context.ts#L1-L16","documentation":"usePiniaSynced reads the SyncedPiniaRuntime via Vue inject using injectKeyPiniaSynced, which is only provided by the app's setupSynced plugin (installed via app.use(synced.vue)). If nothing provides the key, the composable throws rather than silently returning a no-op runtime, because cross-window Pinia synchronization cannot work without it.","triggerScenarios":"Calling usePiniaSynced() in a component/store before (or without) the app installing the synced plugin — e.g. during early setup, in a test that mounts components without createApp().use(synced.vue), or in a secondary window whose bootstrap skipped plugin installation.","commonSituations":"Unit tests mounting components with a bare Pinia; a new Electron utility window that forgot setupSynced; calling the composable at module scope outside a component setup where inject cannot resolve.","solutions":["Install the plugin during app bootstrap: app.use(pinia); app.use(synced.vue).","In tests, build the app with the same plugin installation as production, or provide injectKeyPiniaSynced with a stub runtime.","Ensure usePiniaSynced() is called inside a component setup/effect scope so inject works.","Verify the secondary renderer's entry point runs the shared bootstrap that installs the plugin."],"exampleFix":"// before\nconst app = createApp(App)\napp.use(pinia)\n// after\nconst app = createApp(App)\napp.use(pinia)\napp.use(synced.vue)","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function hasPiniaSynced(): boolean {\n  return inject(injectKeyPiniaSynced) !== undefined\n}","tryCatchPattern":"let runtime: SyncedPiniaRuntime\ntry {\n  runtime = usePiniaSynced()\n} catch {\n  runtime = createNoopSyncedRuntime() // tests / non-synced windows\n}","preventionTips":["Install synced.vue in a shared bootstrap used by every app entry and test harness.","Call usePiniaSynced only inside component setup contexts.","Add a smoke test that mounts the app and asserts the plugin provides the injection key."],"tags":["pinia","vue","dependency-injection","plugin-not-installed"],"backgroundTag":"missing-dependency","analyzedSha":"438a067dde47aa0bdb46c2323d1fe293dc805218","analyzedAt":"2026-09-17T01:14:42.644Z","contentChangedAt":"2026-09-17T01:14:42.644Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}