{"record":{"id":"cc88dda65041d811","repo":"different-ai/openwork","slug":"electron-desktop-helper-is-unavailable-command","errorCode":null,"errorMessage":"Electron desktop helper is unavailable: ${command}","messagePattern":"Electron desktop helper is unavailable: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/app/src/app/lib/desktop.ts","lineNumber":233,"sourceCode":"        platform?: \"darwin\" | \"linux\" | \"windows\";\n        version?: string;\n        evalFatalBootstrapFailure?: string | null;\n      };\n    };\n  }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nasync function invokeElectronHelper<C extends DesktopCommandName>(\n  command: C,\n  ...args: DesktopCommandArgs<C>\n): Promise<DesktopCommandResult<C>> {\n  const invokeDesktop = window.__OPENWORK_ELECTRON__?.invokeDesktop;\n  if (!invokeDesktop) {\n    throw new Error(`Electron desktop helper is unavailable: ${command}`);\n  }\n  return (await invokeDesktop(command, ...args)) as DesktopCommandResult<C>;\n}\n\n// Pure utility — resolves the selected workspace ID from a workspace list\n// payload, handling legacy fields.\nexport function resolveWorkspaceListSelectedId(\n  list: Pick<WorkspaceList, \"selectedId\" | \"activeId\"> | null | undefined,\n): string {\n  return list?.selectedId?.trim() || list?.activeId?.trim() || \"\";\n}\n\n// ---------------------------------------------------------------------------\n// Desktop bridge (Electron IPC proxy)\n// ---------------------------------------------------------------------------\n\n// All bridge methods are implemented via invokeDesktop IPC. The Proxy\n// automatically maps property access to `invokeDesktop(propertyName, ...args)`.","sourceCodeStart":215,"sourceCodeEnd":251,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/apps/app/src/app/lib/desktop.ts#L215-L251","documentation":"invokeElectronHelper is the typed wrapper around the Electron preload bridge `window.__OPENWORK_ELECTRON__.invokeDesktop`. When that bridge is not present on `window` — i.e. the code is not running inside the Electron renderer with the preload script loaded — there is no way to service the command, so the wrapper throws immediately with the requested command name to make the missing-runtime cause obvious. It is a deliberate fail-fast instead of silently returning undefined.","triggerScenarios":"Any typed desktop command routed through invokeElectronHelper — cancel, desktopUploadMultipart, desktopDownloadBinary, result, getDesktopFileIcon, getDesktopApplicationsForFile — executed while `window.__OPENWORK_ELECTRON__` or its `invokeDesktop` method is undefined, such as in a plain browser build, during SSR/SSR hydration, before the Electron preload has attached the bridge, or in an old desktop build lacking the API.","commonSituations":"Running the web (non-Electron) build of the app and clicking a desktop-only action like 'Reveal in Finder' or a file download that uses the desktop multipart upload; an Electron app updated to a renderer whose preload script failed to load (e.g. contextIsolation/sandbox changes) so the bridge never registers; unit or Storybook tests that import desktop.ts and render components without mocking the window bridge.","solutions":["Run the app in the Electron desktop build (or verify the Electron preload script is loaded) so window.__OPENWORK_ELECTRON__.invokeDesktop exists before invoking the command.","Guard the call site with a capability check such as `if (!window.__OPENWORK_ELECTRON__?.invokeDesktop) return;` and show a web-appropriate UI instead of the desktop action.","In tests/storybook, polyfill `window.__OPENWORK_ELECTRON__` with a stub invokeDesktop that returns canned DesktopCommandResult values.","If you are in Electron but still see this, check preload path registration (webPreferences.preload) and console errors from the preload script."],"exampleFix":"// before\nconst icon = await getDesktopFileIcon(path);\n\n// after\nif (!window.__OPENWORK_ELECTRON__?.invokeDesktop) {\n  console.warn(\"Desktop helper unavailable; skipping file icon.\");\n  return null;\n}\nconst icon = await getDesktopFileIcon(path);","handlingStrategy":"try-catch","validationCode":"const canUseDesktop = typeof window !== \"undefined\" && typeof window.__OPENWORK_ELECTRON__?.invokeDesktop === \"function\";","typeGuard":"function hasElectronBridge(w: unknown): w is { __OPENWORK_ELECTRON__: { invokeDesktop: (...args: unknown[]) => Promise<unknown> } } {\n  return typeof window === \"object\" &&\n    typeof (window as { __OPENWORK_ELECTRON__?: unknown }).__OPENWORK_ELECTRON__ === \"object\" &&\n    typeof (window as { __OPENWORK_ELECTRON__?: { invokeDesktop?: unknown } }).__OPENWORK_ELECTRON__?.invokeDesktop === \"function\";\n}","tryCatchPattern":"try {\n  return await invokeElectronHelper(\"getDesktopFileIcon\", path);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith(\"Electron desktop helper is unavailable\")) {\n    return null; // web build: no desktop icons\n  }\n  throw err;\n}","preventionTips":["Gate all desktop-only UI behind a single isDesktopRuntime() capability check.","Mock window.__OPENWORK_ELECTRON__ in test/storybook setups.","Never call desktop helpers during SSR/prerender; guard with typeof window !== \"undefined\".","Keep preload registration (webPreferences.preload) verified in app startup checks."],"tags":["electron","runtime-environment","missing-bridge","desktop-integration"],"backgroundTag":"electron-preload-bridge-unavailable","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}