mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-01 19:42:03 +00:00
fix(skills): reject empty/partial scene files at assembly, not at render (#1629)
A scene worker that errors or is interrupted mid-write leaves an empty (or markup-less) compositions/<scene>.html. existsSync passed, so assemble-index emitted a data-composition-src pointing at it and the failure surfaced much later as the render-compile error "Composition HTML is empty or could not be parsed: compositions/scene-*.html" — the #1 render_error, ~4.7k users/day and climbing. All three assemblers (product-launch-video, faceless-explainer, pr-to-video) now validate scene-file content (non-empty + contains markup) right where they already read it for the duration cross-check, and die with an actionable "re-dispatch that scene worker" message before the broken project can reach a user's render.
This commit is contained in:
@@ -171,7 +171,17 @@ for (const visual of visualClips) {
|
||||
const start = Number(visual.start_s);
|
||||
if (!isFinite(start) || start < 0)
|
||||
die(`${visual.id}: visual start_s invalid (${visual.start_s})`);
|
||||
const rootDur = rootDataDuration(readFileSync(compAbs, "utf8"));
|
||||
// Guard against blank/partial scene files: a worker that errors or is
|
||||
// interrupted mid-write leaves an empty (or markup-less) file that exists but
|
||||
// fails at render with "Composition HTML is empty or could not be parsed".
|
||||
// Catch it here — before emitting data-composition-src — and re-dispatch.
|
||||
const compHtml = readFileSync(compAbs, "utf8");
|
||||
if (!compHtml.trim() || !/<\w/.test(compHtml)) {
|
||||
die(
|
||||
`visual file ${compRel} is empty or has no HTML — the worker for ${visual.id} wrote a blank/partial file. Re-dispatch that scene worker before assembling.`,
|
||||
);
|
||||
}
|
||||
const rootDur = rootDataDuration(compHtml);
|
||||
if (rootDur == null) {
|
||||
anomalies.push(
|
||||
`${visual.id}: could not read root data-duration from ${compRel} — skipped duration cross-check`,
|
||||
|
||||
@@ -171,7 +171,17 @@ for (const visual of visualClips) {
|
||||
const start = Number(visual.start_s);
|
||||
if (!isFinite(start) || start < 0)
|
||||
die(`${visual.id}: visual start_s invalid (${visual.start_s})`);
|
||||
const rootDur = rootDataDuration(readFileSync(compAbs, "utf8"));
|
||||
// Guard against blank/partial scene files: a worker that errors or is
|
||||
// interrupted mid-write leaves an empty (or markup-less) file that exists but
|
||||
// fails at render with "Composition HTML is empty or could not be parsed".
|
||||
// Catch it here — before emitting data-composition-src — and re-dispatch.
|
||||
const compHtml = readFileSync(compAbs, "utf8");
|
||||
if (!compHtml.trim() || !/<\w/.test(compHtml)) {
|
||||
die(
|
||||
`visual file ${compRel} is empty or has no HTML — the worker for ${visual.id} wrote a blank/partial file. Re-dispatch that scene worker before assembling.`,
|
||||
);
|
||||
}
|
||||
const rootDur = rootDataDuration(compHtml);
|
||||
if (rootDur == null) {
|
||||
anomalies.push(
|
||||
`${visual.id}: could not read root data-duration from ${compRel} — skipped duration cross-check`,
|
||||
|
||||
@@ -125,7 +125,17 @@ for (const { sid, scene } of playOrder) {
|
||||
`${sid}: group_spec estimatedDuration_s missing or non-positive (${scene.estimatedDuration_s})`,
|
||||
);
|
||||
}
|
||||
const rootDur = rootDataDuration(readFileSync(compAbs, "utf8"));
|
||||
// Guard against blank/partial scene files: a worker that errors or is
|
||||
// interrupted mid-write leaves an empty (or markup-less) file that exists but
|
||||
// fails at render with "Composition HTML is empty or could not be parsed".
|
||||
// Catch it here — before emitting data-composition-src — and re-dispatch.
|
||||
const compHtml = readFileSync(compAbs, "utf8");
|
||||
if (!compHtml.trim() || !/<\w/.test(compHtml)) {
|
||||
die(
|
||||
`scene file ${compRel} is empty or has no HTML — the worker for ${sid} wrote a blank/partial file. Re-dispatch that scene worker before assembling.`,
|
||||
);
|
||||
}
|
||||
const rootDur = rootDataDuration(compHtml);
|
||||
if (rootDur == null) {
|
||||
anomalies.push(
|
||||
`${sid}: could not read root data-duration from ${compRel} — skipped duration cross-check`,
|
||||
|
||||
Reference in New Issue
Block a user