heygen-com/hyperframes · warning
Speech was generated but metadata could not be read. Check t
Error message
Speech was generated but metadata could not be read. Check the output file manually.
What it means
Synthesis actually succeeded — the WAV exists at outputPath — but JSON.parse on the last line of the Python stdout threw a SyntaxError. The inline script prints a JSON metadata object as its final line; if Python emitted a warning, traceback fragment, or print AFTER that line (or if the JSON was malformed), parsing fails. The library deliberately surfaces a clearer message rather than re-throwing the raw SyntaxError or fabricating metadata.
Source
Thrown at packages/cli/src/tts/synthesize.ts:199
const jsonLine = lines[lines.length - 1] ?? "";
const result: {
outputPath: string;
sampleRate: number;
durationSeconds: number;
langApplied: boolean;
} = JSON.parse(jsonLine);
return {
outputPath: result.outputPath,
sampleRate: result.sampleRate,
durationSeconds: result.durationSeconds,
langApplied: result.langApplied,
};
} catch (err: unknown) {
// If the error is our own JSON parse failure but the file was created,
// re-throw with a clearer message rather than returning fabricated data
if (err instanceof SyntaxError && existsSync(outputPath)) {
throw new Error(
"Speech was generated but metadata could not be read. Check the output file manually.",
);
}
let detail = "";
if (err && typeof err === "object" && "stderr" in err) {
const stderr = String(err.stderr).trim();
if (stderr) detail = `\n${stderr.slice(-500)}`;
}
throw new Error(`Speech synthesis failed${detail}`);
}
}
View on GitHub (pinned to c2996c8626)
Solutions
- The audio file was created — use it directly; the metadata (sampleRate, durationSeconds) can be re-derived from the WAV header if needed.
- Set PYTHONWARNINGS=ignore to suppress warnings that may print to stdout after the JSON line.
- Inspect the cached synth-v2.py: confirm the json.dumps print is the absolute last statement with no trailing code.
- Capture and read the Python stdout yourself to see what came after the JSON line and report the noise source.
Defensive patterns
Strategy: fallback
Try / catch
try {
return await synthesize(text, out, { voice });
} catch (err) {
if (err instanceof Error && /metadata could not be read/.test(err.message) && existsSync(out)) {
// synthesis succeeded — derive metadata from the WAV header instead of failing
return { outputPath: out, sampleRate: readWavSampleRate(out), durationSeconds: readWavDuration(out), langApplied: false };
}
throw err;
} Prevention
- Set PYTHONWARNINGS=ignore to keep warnings off stdout where they can follow the JSON line.
- If you control the pipeline, treat the existing WAV as success even when metadata is unreadable.
- Pin kokoro-onnx to a version known to print only the JSON line to stdout.
When it happens
Trigger: A Python warning (e.g. from torch/onnxruntime) printed to stdout AFTER the JSON line; the script printed a deprecation warning without a trailing newline ordering; a newer kokoro-onnx prints a progress/info line after the JSON; multi-line stdout where the 'last line' heuristic grabs a partial JSON fragment.
Common situations: User upgraded kokoro-onnx and the new version logs to stdout; PYTHONUNBUFFERED or a logging config that emits to stdout; a NumPy/torch ABI warning that prints at import time after the metadata print; stderr/stdout interleaving under some CI log capturers.
Related errors
- Synthesis completed but no output file was created
- Speech synthesis failed${detail}
- Python 3 is required for text-to-speech. Install Python 3.10
- The kokoro-onnx package is not installed. Run: pip install k
- [validateConfig] config: Step Functions execution input is n
AI-assisted analysis of heygen-com/hyperframes@c2996c8626 (2026-08-12).
Data as JSON: /api/errors/2b032a093303f569.
Report an issue: GitHub.