{"record":{"id":"9af7cf51ee1fb622","repo":"moeru-ai/airi","slug":"file-input-is-required-for-transcription","errorCode":null,"errorMessage":"File input is required for transcription.","messagePattern":"File input is required for transcription\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/stage-ui/src/stores/modules/hearing.ts","lineNumber":499,"sourceCode":"        if (features.supportsStreamInput && !normalizedInput.inputAudioStream && normalizedInput.file) {\n          const streamResult = streamExecutor({\n            ...request,\n            file: normalizedInput.file,\n          } as Parameters<typeof streamExecutor>[0])\n          emitSucceeded(0, true)\n          return {\n            mode: 'stream',\n            ...streamResult,\n          }\n        }\n\n        if (!features.supportsGenerate || !normalizedInput.file) {\n          throw new Error('No compatible input provided for streaming transcription.')\n        }\n      }\n\n      if (!normalizedInput.file) {\n        throw new Error('File input is required for transcription.')\n      }\n\n      const useVerboseJson = !format && confidenceThreshold.value > CONFIDENCE_THRESHOLD_DISABLED\n      const response = await generateTranscription({\n        ...provider.transcription(model, options?.providerOptions),\n        file: normalizedInput.file,\n        fileName: resolveTranscriptionFileName(normalizedInput.file, normalizedInput.fileName),\n        responseFormat: useVerboseJson ? 'verbose_json' : format,\n      })\n\n      if (useVerboseJson) {\n        if (response.segments) {\n          verboseJsonNotSupported.value = false\n          const filteredText = filterTranscriptionByConfidence(response.segments, confidenceThreshold.value)\n          emitSucceeded(filteredText.length, false)\n          return {\n            mode: 'generate',\n            ...response,","sourceCodeStart":481,"sourceCodeEnd":517,"githubUrl":"https://github.com/moeru-ai/airi/blob/f679616c34f1cf6d282c8d64264242af944b3fed/packages/stage-ui/src/stores/modules/hearing.ts#L481-L517","documentation":"The non-streaming transcription path calls generateTranscription, which requires normalizedInput.file. When the caller supplied no file — only a stream input on a provider without stream support, or nothing at all after input normalization — this precondition throws before any provider request is made. It is the plain 'you gave me no audio file' guard for generate-mode STT.","triggerScenarios":"Using a generate-only (non-stream) STT provider while only an inputAudioStream is available; microphone recording failing so no Blob/File was produced; calling transcribe with only options and no audio input; a file-only provider receiving a stream-oriented request object.","commonSituations":"Live-mic flows wired to providers that only support batch file transcription; audio recorder errors swallowed upstream so downstream sees an empty input; programmatic use of the hearing store without attaching captured audio.","solutions":["Produce and pass a file: record the audio to a Blob/File before calling transcription.","Choose a provider that supports stream input when you only have a live stream.","Validate that a file exists in normalized input before invoking transcription and surface a capture error early.","Fix the recording pipeline when it silently yields no file."],"exampleFix":"// before\nconst result = await hearing.transcribe(model, {})\n\n// after\nif (!recordedBlob) {\n  toast.info('No recorded audio to transcribe')\n  return\n}\nconst result = await hearing.transcribe(model, { file: recordedBlob })","handlingStrategy":"validation","validationCode":"if (!input.file) {\n  toast.info('No recorded audio to transcribe')\n  return\n}\nawait hearing.transcribe(model, { file: input.file })","typeGuard":"function hasTranscribableFile(input: unknown): input is { file: Blob } {\n  return typeof input === 'object' && input !== null\n    && input.file instanceof Blob\n    && input.file.size > 0\n}","tryCatchPattern":"try {\n  const result = await hearing.transcribe(model, input)\n}\ncatch (error) {\n  if (errorMessageFrom(error) === 'File input is required for transcription.') {\n    // capture produced nothing: reset the recorder instead of showing a hard error\n    resetRecorder()\n    return\n  }\n  throw error\n}","preventionTips":["Ensure the recorder emits a non-empty Blob before enabling transcription.","Match the input type to provider capabilities: files for generate-only providers, streams for stream-input providers.","Validate normalized input in the hearing pipeline before dispatching to the provider.","Log capture-layer errors instead of swallowing them so empty files are diagnosable."],"tags":["stt","transcription","validation","file-input"],"backgroundTag":"missing-input-file","analyzedSha":"f679616c34f1cf6d282c8d64264242af944b3fed","analyzedAt":"2026-08-18T17:29:58.153Z","contentChangedAt":"2026-08-18T17:29:58.153Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}