{"record":{"id":"d1b924681279cd53","repo":"moeru-ai/airi","slug":"electron-ipcrenderer-is-not-available-pass-it-exp","errorCode":null,"errorMessage":"Electron ipcRenderer is not available. Pass it explicitly to useElectronEventaContext().","messagePattern":"Electron ipcRenderer is not available\\. Pass it explicitly to useElectronEventaContext\\(\\)\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/electron-vueuse/src/composables/use-electron-eventa-context.ts","lineNumber":20,"sourceCode":"import type { ShallowRef } from 'vue'\n\nimport { defineInvoke } from '@moeru/eventa'\nimport { createContext } from '@moeru/eventa/adapters/electron/renderer'\nimport { shallowRef } from 'vue'\n\ntype EventaContext = ReturnType<typeof createContext>['context']\ntype IpcRendererLike = Parameters<typeof createContext>[0]\n\nlet sharedContext: EventaContext | undefined\n\nfunction resolveIpcRenderer(ipcRenderer?: IpcRendererLike): IpcRendererLike {\n  if (ipcRenderer) {\n    return ipcRenderer\n  }\n\n  const globalIpcRenderer = (globalThis as { window?: { electron?: { ipcRenderer?: IpcRendererLike } } }).window?.electron?.ipcRenderer\n  if (!globalIpcRenderer) {\n    throw new Error('Electron ipcRenderer is not available. Pass it explicitly to useElectronEventaContext().')\n  }\n\n  return globalIpcRenderer\n}\n\nexport function getElectronEventaContext(ipcRenderer?: IpcRendererLike): EventaContext {\n  sharedContext ??= createContext(resolveIpcRenderer(ipcRenderer)).context\n  return sharedContext\n}\n\nexport function useElectronEventaContext(ipcRenderer?: IpcRendererLike): ShallowRef<EventaContext> {\n  return shallowRef(getElectronEventaContext(ipcRenderer))\n}\n\nexport function useElectronEventaInvoke<Res, Req = undefined, ResErr = Error, ReqErr = Error>(invoke: InvokeEventa<Res, Req, ResErr, ReqErr>, context?: EventaContext) {\n  return defineInvoke(context ?? getElectronEventaContext(), invoke)\n}\n","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/moeru-ai/airi/blob/27111382b4a79a7e983289d6e983a06af185ed0f/packages/electron-vueuse/src/composables/use-electron-eventa-context.ts#L2-L38","documentation":"Thrown by resolveIpcRenderer() in @proj-airi/electron-vueuse when no ipcRenderer is passed explicitly and globalThis.window.electron.ipcRenderer is absent. The shared eventa context is created lazily from an ipcRenderer, so without one the context cannot be built. Common in preload-bridge setups where window.electron is not injected.","triggerScenarios":"Calling useElectronEventaContext() or getElectronEventaContext() with no argument in a renderer where the preload script did not expose window.electron.ipcRenderer; calling it outside an Electron renderer (e.g. in a plain web/Vite dev context, SSR, or a Node test).","commonSituations":"Preload script uses contextIsolation without exposeInMainWorld('electron', { ipcRenderer }); running component tests in jsdom/happy-dom without mocking the bridge; a Vue component shared between web and Electron that calls the composable unconditionally; Electron upgrade that changed the bridge shape.","solutions":["In the preload script, expose the ipcRenderer: contextBridge.exposeInMainWorld('electron', { ipcRenderer: { send, on, invoke, ... } }).","Pass the ipcRenderer explicitly: useElectronEventaContext(window.electron.ipcRenderer).","Guard the composable call behind an isElectron check in shared components.","In tests, mock globalThis.window.electron.ipcRenderer before mounting."],"exampleFix":"// before (preload)\ncontextBridge.exposeInMainWorld('api', { foo })\n// renderer: useElectronEventaContext() throws\n// after\ncontextBridge.exposeInMainWorld('electron', { ipcRenderer: { send: ipcRenderer.send.bind(ipcRenderer), on: ipcRenderer.on.bind(ipcRenderer), invoke: ipcRenderer.invoke.bind(ipcRenderer) } })","handlingStrategy":"validation","validationCode":"function resolveIpc(): IpcRendererLike {\n  const explicit = window.electron?.ipcRenderer\n  if (!explicit) throw new Error('ipcRenderer missing; check the preload bridge exposes window.electron.ipcRenderer')\n  return explicit\n}\n\nuseElectronEventaContext(resolveIpc())","typeGuard":"function hasIpcRenderer(g: unknown): g is { electron: { ipcRenderer: object } } {\n  return !!g && typeof g === 'object' && 'electron' in (g as any) && !!(g as any).electron?.ipcRenderer\n}","tryCatchPattern":"try {\n  useElectronEventaContext()\n} catch (error) {\n  if (error instanceof Error && error.message.includes('ipcRenderer is not available')) {\n    // fall back to a no-op context or show 'Electron bridge missing' UI\n  } else throw error\n}","preventionTips":["Expose window.electron.ipcRenderer via contextBridge.exposeInMainWorld in the preload.","Guard shared components with an isElectron check before calling the composable.","Mock globalThis.window.electron.ipcRenderer in renderer unit tests."],"tags":["electron","eventa","ipc","preload","vue"],"backgroundTag":null,"analyzedSha":"27111382b4a79a7e983289d6e983a06af185ed0f","analyzedAt":"2026-08-12T18:33:34.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}