heygen-com/hyperframes · error
Unrecognized JSON transcript format. Expected whisper.cpp (t
Error message
Unrecognized JSON transcript format. Expected whisper.cpp (transcription[].tokens), OpenAI API (words[]), or normalized ([{text, start, end}]). What it means
Thrown by detectJsonFormat when a .json transcript file was successfully parsed as JSON but its structure doesn't match any of the three recognized formats: whisper-cpp (object with a transcription array), OpenAI API (object with a words array), or normalized words-json (array of objects with text and start fields). This is a content-level validation, not a JSON syntax error.
Source
Thrown at packages/cli/src/whisper/normalize.ts:54
*/
export function detectFormat(filePath: string): TranscriptFormat {
const ext = extname(filePath).toLowerCase();
if (ext === ".srt") return "srt";
if (ext === ".vtt") return "vtt";
if (ext === ".json") return detectJsonFormat(JSON.parse(readFileSync(filePath, "utf-8")));
throw new Error(`Unsupported transcript file extension: ${ext}. Use .json, .srt, or .vtt`);
}
function detectJsonFormat(raw: unknown): TranscriptFormat {
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
const obj = raw as Record<string, unknown>;
if (obj.transcription && Array.isArray(obj.transcription)) return "whisper-cpp";
if (obj.words && Array.isArray(obj.words)) return "openai";
}
if (Array.isArray(raw) && raw[0]?.text !== undefined && raw[0]?.start !== undefined) {
return "words-json";
}
throw new Error(
"Unrecognized JSON transcript format. Expected whisper.cpp (transcription[].tokens), " +
"OpenAI API (words[]), or normalized ([{text, start, end}]).",
);
}
// ---------------------------------------------------------------------------
// Parsers
// ---------------------------------------------------------------------------
/**
* Rejoin word fragments that whisper splits across tokens:
* - Single capital + lowercase continuation: C + aught -> Caught, G + onna -> Gonna
* - Word ending in consonant + in': shin + in' -> shinin', hid + in' -> hidin'
*/
function mergeFragments(words: Word[]): void {
for (let i = 0; i < words.length - 1; i++) {
const curr = words[i];
const next = words[i + 1];View on GitHub (pinned to c2996c8626)
Solutions
- Inspect the JSON structure and map it to one of the three supported schemas (whisper-cpp transcription[], OpenAI words[], or normalized [{text, start, end}]).
- Convert the transcript to SRT or VTT format instead, which has a simpler, well-defined structure.
- If using whisper-cpp output, ensure you're using the correct output format flag (--output-json with transcription field).
- For custom JSON, transform it to the normalized [{text, start, end}] format before passing.
Example fix
// before: [{"word": "hello", "ts": 0}] (unrecognized schema)
// after: [{"text": "hello", "start": 0, "end": 0.5}] (normalized words-json) Defensive patterns
Strategy: type-guard
Validate before calling
function isRecognizedJsonFormat(raw: unknown): boolean {
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
const obj = raw as Record<string, unknown>;
if (Array.isArray(obj.transcription) || Array.isArray(obj.words)) return true;
}
if (Array.isArray(raw) && raw[0]?.text !== undefined && raw[0]?.start !== undefined) return true;
return false;
} Type guard
function isNormalizedWordsArray(raw: unknown): raw is Array<{ text: string; start: number; end: number }> {
return Array.isArray(raw) && raw.every(
(item) => typeof item === "object" && item !== null &&
typeof item.text === "string" &&
typeof item.start === "number" &&
typeof item.end === "number",
);
} Try / catch
try {
const format = detectFormat(filePath);
} catch (err) {
if (err instanceof Error && err.message.includes("Unrecognized JSON transcript format")) {
console.error(`${err.message}. Convert to SRT/VTT or use a supported JSON schema.`);
process.exit(1);
}
throw err;
} Prevention
- Validate the JSON structure against the three supported schemas before passing it.
- When in doubt, convert transcripts to SRT or VTT — simpler and universally parseable.
- Inspect the JSON file's top-level keys: look for transcription[], words[], or [{text, start, end}].
When it happens
Trigger: The JSON file is valid JSON but has a different schema — e.g. a raw array without text/start keys, an object with a segments array but no transcription or words field, or a proprietary caption format. Also triggered by an empty JSON object or empty array.
Common situations: Using a transcript from a tool that exports a different JSON schema (e.g. Deepgram, AssemblyAI, Rev); an incomplete or truncated export; a manually-created JSON with wrong field names; a whisper-cpp output from a version that changed its schema.
Related errors
- Unsupported transcript file extension: ${ext}. Use .json, .s
- [validateConfig] config: Step Functions execution input is n
- [validateConfig] config: Step Functions execution input is n
- invalid-vars
- ${source}: ${errorMessage(error)}
AI-assisted analysis of heygen-com/hyperframes@c2996c8626 (2026-08-12).
Data as JSON: /api/errors/b4d42a198aecf510.
Report an issue: GitHub.