moeru-ai/airi · error · Error

Web Speech API is not available in this environment. It requ

Error message

Web Speech API is not available in this environment. It requires a browser context with SpeechRecognition support (Chrome, Edge, Safari).

What it means

Thrown by createWebSpeechAPIProvider() when the running environment has no window object or window lacks both SpeechRecognition and webkitSpeechRecognition. The Web Speech API is a browser-only, vendor-specific capability; without it the provider cannot construct a transcription client, so construction aborts. This is an environment capability check, not a runtime error.

Source

Thrown at packages/stage-ui/src/libs/providers/providers/browser-web-speech-api/provider.ts:61

/**
 * Web Speech API Speech Recognition provider
 *
 * This is a free, browser-native STT solution that requires no API keys.
 * Available in Chrome, Edge, Safari, and other Chromium-based browsers.
 *
 * Limitations:
 * - Only works in browser contexts (Electron renderer, web browsers)
 * - Requires user permission for microphone access
 * - Language support depends on browser implementation
 * - Not available in Node.js or Tauri main process
 */
export function createWebSpeechAPIProvider(): TranscriptionProviderWithExtraOptions<string, WebSpeechAPIExtraOptions> {
  // Check if Web Speech API is available
  const isAvailable = typeof window !== 'undefined'
    && ('webkitSpeechRecognition' in window || 'SpeechRecognition' in window)

  if (!isAvailable) {
    throw new Error('Web Speech API is not available in this environment. It requires a browser context with SpeechRecognition support (Chrome, Edge, Safari).')
  }

  const SpeechRecognition = (window as any).SpeechRecognition || (window as any).webkitSpeechRecognition

  return {
    transcription: (model: string, extraOptions?: WebSpeechAPIExtraOptions) => {
      return {
        baseURL: 'about:blank', // Web Speech API doesn't use HTTP endpoints
        model: model || 'web-speech-api',
        fetch: async (_request: RequestInfo | URL, _init?: RequestInit) => {
          // Web Speech API does not support file-based transcription - it only supports live streaming
          // Check if a file is provided in the request body and reject it
          if (_init?.body) {
            // If body is FormData, it likely contains a file
            // If body is a Blob/File, it's definitely a file
            const body = _init.body
            if (body instanceof FormData || body instanceof Blob || body instanceof File) {
              const error = new Error('Web Speech API does not support file-based transcription. It only supports live streaming from a MediaStream. Please use the streaming transcription API or select a different provider that supports file-based transcription.')

View on GitHub (pinned to 27111382b4)

Solutions

  1. Only construct the provider in a supported browser renderer context (Chromium-based browser, Edge, Safari, Electron renderer with the API enabled).
  2. Guard construction: check 'SpeechRecognition' in window || 'webkitSpeechRecognition' in window before calling createWebSpeechAPIProvider().
  3. In Firefox or unsupported environments, choose a different transcription provider (e.g. Whisper, Aliyun NLS).
  4. For SSR/build, dynamic-import the provider inside an onMounted or client-only guard so it is never evaluated in Node.

Example fix

// before
const provider = createWebSpeechAPIProvider()
// after
const canUseWebSpeech = typeof window !== 'undefined'
  && ('SpeechRecognition' in window || 'webkitSpeechRecognition' in window)
if (!canUseWebSpeech)
  throw new Error('Web Speech API unsupported in this browser; pick another transcription provider')
const provider = createWebSpeechAPIProvider()
Defensive patterns

Strategy: type-guard

Validate before calling

function isWebSpeechSupported(): boolean {
  return typeof window !== 'undefined'
    && ('webkitSpeechRecognition' in window || 'SpeechRecognition' in window)
}
// before constructing the provider:
if (!isWebSpeechSupported()) {
  // pick another transcription provider; do not call createWebSpeechAPIProvider()
}

Type guard

function isWebSpeechSupported(): boolean {
  return typeof window !== 'undefined'
    && ('webkitSpeechRecognition' in window || 'SpeechRecognition' in window)
}

Try / catch

try {
  const provider = createWebSpeechAPIProvider()
}
catch (err) {
  if (err instanceof Error && err.message.startsWith('Web Speech API is not available')) {
    // fall back to a server-side transcription provider (Whisper, Aliyun NLS)
  }
  else throw err
}

Prevention

When it happens

Trigger: createWebSpeechAPIProvider() is called where typeof window === 'undefined' (Node.js, SSR, Tauri/Electron main process, a Web Worker) or in a browser without SpeechRecognition (Firefox, some Chromium embedded views with the flag disabled).

Common situations: Importing the provider during SSR/Node build or in the Electron main process. Running in Firefox, which lacks SpeechRecognition. Headless test environment (jsdom) without the API. Embedded WebView with the speech API disabled.

Related errors


AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12). Data as JSON: /api/errors/60fa253f0ca838ff. Report an issue: GitHub.