vercel/ai · error · UnsupportedFunctionalityError

non-streaming transcription with ${this.modelId}

Error message

non-streaming transcription with ${this.modelId}

What it means

The ElevenLabs transcription model throws this when doGenerate (non-streaming transcription) is called with a model ID that is a realtime-only transcription model (per isRealtimeTranscriptionModelId). Realtime models like scribe_v1_realtime only support WebSocket streaming; they cannot be used for one-shot HTTP transcription.

Source

Thrown at packages/elevenlabs/src/elevenlabs-transcription-model.ts:185

            key as keyof ElevenLabsTranscriptionAPITypes
          ];
        if (value !== undefined) {
          formData.append(key, String(value));
        }
      }
    }

    return {
      formData,
      warnings,
    };
  }

  async doGenerate(
    options: Parameters<TranscriptionModelV4['doGenerate']>[0],
  ): Promise<Awaited<ReturnType<TranscriptionModelV4['doGenerate']>>> {
    if (isRealtimeTranscriptionModelId(this.modelId)) {
      throw new UnsupportedFunctionalityError({
        functionality: `non-streaming transcription with ${this.modelId}`,
      });
    }

    const currentDate = this.config._internal?.currentDate?.() ?? new Date();
    const { formData, warnings } = await this.getArgs(options);

    const {
      value: response,
      responseHeaders,
      rawValue: rawResponse,
    } = await postFormDataToApi({
      url: this.config.url({
        path: '/v1/speech-to-text',
        modelId: this.modelId,
      }),
      headers: combineHeaders(this.config.headers?.(), options.headers),
      formData,

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Use a batch/non-realtime model id such as 'scribe_v1' for non-streaming transcription.
  2. If you need realtime results, use doStream with the realtime model instead of doGenerate.
  3. Check the model id with isRealtimeTranscriptionModelId-style logic before choosing the call path.

Example fix

// before
const model = elevenlabs.transcriptionModel('scribe_v1_realtime');
await model.doGenerate(options);
// after
const model = elevenlabs.transcriptionModel('scribe_v1');
await model.doGenerate(options);
Defensive patterns

Strategy: validation

Validate before calling

const REALTIME_IDS = ['scribe_v1_realtime'];
function assertBatchModel(modelId: string) {
  if (REALTIME_IDS.some(id => modelId.includes(id))) {
    throw new Error(`${modelId} only supports streaming transcription`);
  }
}
assertBatchModel('scribe_v1'); // before calling doGenerate

Type guard

function isRealtimeModelId(modelId: string): boolean {
  return modelId.includes('realtime');
}

Prevention

When it happens

Trigger: Calling generateText/transcribe-style doGenerate with providerOptions selecting a realtime model id such as 'scribe_v1_realtime' through elevenlabs.transcriptionModel('scribe_v1_realtime').

Common situations: Developers copy a realtime model id from ElevenLabs docs into a non-streaming transcription call, or dynamically switch model ids and accidentally route a realtime model into the batch transcription path.

Related errors


AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30). Data as JSON: /api/errors/0430458efc38e480. Report an issue: GitHub.