{"record":{"id":"19c598f16ea6e2fd","repo":"moeru-ai/airi","slug":"apple-speech-transcription-requires-the-electron-d","errorCode":null,"errorMessage":"Apple Speech transcription requires the Electron desktop app.","messagePattern":"Apple Speech transcription requires the Electron desktop app\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/stage-ui/src/libs/providers/providers/apple-speech/index.ts","lineNumber":61,"sourceCode":"}\n\nasync function createAppleSpeechConfigSchema(context: ProviderConfigContext<AppleSpeechConfig>) {\n  const { t } = context\n  const localeOptions = await listAppleSpeechLocaleOptions(context)\n  return appleSpeechConfigSchema.extend({\n    locale: appleSpeechConfigSchema.shape.locale.meta({\n      type: 'select',\n      labelLocalized: t('settings.pages.providers.provider.apple-speech-transcription.fields.locale.label'),\n      descriptionLocalized: t('settings.pages.providers.provider.apple-speech-transcription.fields.locale.description'),\n      placeholderLocalized: t('settings.pages.providers.provider.apple-speech-transcription.fields.locale.placeholder'),\n      options: localeOptions,\n    }),\n  })\n}\n\nfunction createRendererAppleSpeechProvider(config: AppleSpeechConfig): AIRIAppleSpeechProvider {\n  if (typeof window === 'undefined' || !isElectronWindow(window))\n    throw new Error('Apple Speech transcription requires the Electron desktop app.')\n\n  const eventa = createContext(window.electron.ipcRenderer)\n  const provider = createElectronAppleSpeechProvider({ context: eventa.context })\n  const configuredLocale = config.locale?.trim() || 'en-US'\n\n  return {\n    transcription(_model, requestOptions = {}) {\n      const locale = requestOptions.locale?.trim() || configuredLocale\n      return {\n        ...provider.transcription({ locale, transcriber: 'automatic' }),\n        ...requestOptions,\n        inputSampleRate: requestOptions.inputSampleRate ?? 16000,\n      }\n    },\n    dispose() {\n      eventa.dispose()\n    },\n  }","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/moeru-ai/airi/blob/f679616c34f1cf6d282c8d64264242af944b3fed/packages/stage-ui/src/libs/providers/providers/apple-speech/index.ts#L43-L79","documentation":"createRendererAppleSpeechProvider throws when window is undefined or is not an Electron renderer (isElectronWindow check fails). Apple Speech transcription runs via native macOS APIs exposed over Electron IPC, so the provider can only be constructed inside the Electron desktop app.","triggerScenarios":"Calling createRendererAppleSpeechProvider (or a factory that routes to it) in a plain browser tab, SSR, mobile webview, or a non-Electron environment where window.electron.ipcRenderer is absent.","commonSituations":"stage-web or stage-pocket builds accidentally selecting the Apple Speech provider; unit tests running in Node/SSR without an Electron mock; feature flags or provider settings carried over from desktop to web; SSR/prerendering touching provider construction.","solutions":["Only instantiate the Apple Speech provider when running inside Electron (guard with the same isElectronWindow/environment detection used elsewhere in the app).","Check provider selection logic / user settings that route to Apple Speech on non-desktop builds.","In tests, mock the Electron window (window.electron.ipcRenderer) or skip the suite outside Electron.","Fallback to a cross-platform transcription provider when not on Electron."],"exampleFix":"// before\nconst provider = createRendererAppleSpeechProvider(config)\n\n// after\nconst provider = typeof window !== 'undefined' && isElectronWindow(window)\n  ? createRendererAppleSpeechProvider(config)\n  : createWebSpeechProvider(config)","handlingStrategy":"type-guard","validationCode":"if (typeof window !== 'undefined' && isElectronWindow(window)) {\n  provider = createRendererAppleSpeechProvider(config)\n} else {\n  provider = createCrossPlatformTranscriptionProvider(config)\n}","typeGuard":"function canUseAppleSpeech(): boolean {\n  return typeof window !== 'undefined' && isElectronWindow(window)\n}","tryCatchPattern":"try {\n  provider = createRendererAppleSpeechProvider(config)\n} catch (err) {\n  if (err instanceof Error && err.message.includes('requires the Electron desktop app')) {\n    provider = createFallbackTranscriptionProvider(config)\n  } else throw err\n}","preventionTips":["Gate provider selection by runtime (Electron vs web vs mobile) in settings UI, not just by user choice.","Skip Apple Speech in SSR/prerender paths.","In tests, detect the Electron mock and conditionally skip or stub the suite."],"tags":["apple-speech","electron","environment-check","provider"],"backgroundTag":"unsupported-platform","analyzedSha":"f679616c34f1cf6d282c8d64264242af944b3fed","analyzedAt":"2026-08-28T13:11:01.995Z","contentChangedAt":"2026-08-28T13:11:01.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}