heygen-com/hyperframes · error
Unsupported file type: ${ext}
Error message
Unsupported file type: ${ext} What it means
Thrown by transcribe() when the input file's extension matches neither AUDIO_EXTENSIONS (.mp3/.wav/.m4a/.aac/.ogg/.flac) nor VIDEO_EXTENSIONS (.mp4/.webm/.mov/.mkv/.avi). The lowercased extension is interpolated into the message so you can see exactly what was rejected. This is a hard gate: only those two extension sets are accepted, decided by extname() alone (not by file content / MIME sniffing).
Source
Thrown at packages/cli/src/whisper/transcribe.ts:435
});
// 3. Prepare audio
let wavPath: string;
const ext = extname(inputPath).toLowerCase();
if (isAudioFile(inputPath)) {
options?.onProgress?.("Preparing audio...");
wavPath = prepareAudio(inputPath);
} else if (isVideoFile(inputPath)) {
if (!hasFFmpeg()) {
throw new Error(
`ffmpeg is required to extract audio from video. Install: ${getFFmpegInstallHint()}`,
);
}
options?.onProgress?.("Extracting audio from video...");
wavPath = extractAudio(inputPath);
} else {
throw new Error(`Unsupported file type: ${ext}`);
}
// 4. Detect language and ensure correct model
let effectiveModel = model;
let effectiveModelPath = modelPath;
let detectedLanguage = options?.language ?? null;
// Only auto-detect language when using a multilingual model.
// .en models always report "en" regardless of actual language, so detection
// would be a no-op. If the user chose .en, they want English.
if (!detectedLanguage && !effectiveModel.endsWith(".en")) {
options?.onProgress?.("Detecting language...");
detectedLanguage = detectLanguage(whisper.executablePath, effectiveModelPath, wavPath);
}
if (detectedLanguage && detectedLanguage !== "en" && effectiveModel.endsWith(".en")) {
const multilingualModel = effectiveModel.replace(/\.en$/, "");
options?.onProgress?.(View on GitHub (pinned to c2996c8626)
Solutions
- Check the file extension against the accepted sets and convert the source to a supported format first (e.g. ffmpeg -i in.opus out.wav, or transcode video to .mp4).
- If the file genuinely is supported audio/video with a non-listed extension, rename or transcode it to one of the accepted extensions before calling transcribe().
- Confirm the path points at a file, not a directory — extname on a directory yields '' and falls through to this branch.
- Request/confirm whether your container should be added to AUDIO_EXTENSIONS or VIDEO_EXTENSIONS upstream if it is a common format HyperFrames should support.
Example fix
// before
await transcribe("./recording.opus", "./out"); // throws Unsupported file type: .opus
// after — transcode to a supported extension first
import { execFileSync } from "node:child_process";
execFileSync("ffmpeg", ["-y", "-i", "./recording.opus", "-ar", "16000", "-ac", "1", "./recording.wav"]);
await transcribe("./recording.wav", "./out"); Defensive patterns
Strategy: validation
Validate before calling
import { extname } from "node:path";
const AUDIO = new Set([".mp3",".wav",".m4a",".aac",".ogg",".flac"]);
const VIDEO = new Set([".mp4",".webm",".mov",".mkv",".avi"]);
function isTranscribable(p: string): boolean {
const ext = extname(p).toLowerCase();
return AUDIO.has(ext) || VIDEO.has(ext);
}
if (!isTranscribable(inputPath)) throw new Error(`unsupported extension ${extname(inputPath)}`); Type guard
function isTranscribableFile(p: string): boolean {
const ext = extname(p).toLowerCase();
return AUDIO.has(ext) || VIDEO.has(ext);
} Try / catch
try { await transcribe(p, out); }
catch (err) { if (/Unsupported file type/.test(String(err))) { /* convert source */ } else throw err; } Prevention
- Validate the extension against the accepted sets before calling transcribe().
- Transcode unusual containers (opus, m2ts) to .wav or .mp4 first.
- Ensure the path is a file, not a directory.
When it happens
Trigger: Passing a file whose extname() is outside both sets — e.g. .opus, .wma, .aiff, .ts, .m2ts, .3gp, .gif, .bmp, a dotfile with no extension, or a path where the extension is upper-case-mangled after a manual toLowerCase bug. A path that is actually a directory also lands here because extname returns ''.
Common situations: User drags a .mov exported from a phone renamed to .MOV (covered by toLowerCase) but more often an unusual container like .opus audio or .m2ts video; pointing transcribe at a still image or a text file by mistake; a pipeline that auto-generates a filename with no extension.
Related errors
- Audio file too large for headless analysis (${mb}MB > ${MAX_
- ffmpeg is required to extract audio from video. Install: ${g
- Whisper did not produce output. Check the input file.
- Unknown effect type: ${type}
- Node ${i} has unknown effect type: ${String(node.type)}
AI-assisted analysis of heygen-com/hyperframes@c2996c8626 (2026-08-12).
Data as JSON: /api/errors/9ed7c80d33db9970.
Report an issue: GitHub.