Skip to content

Commit 2577aaf

Browse files
fix(studio): ignore stale failed sidecars for existing renders (#2621)
* fix(studio): ignore stale failed sidecars for existing renders * style: format stale render metadata test
1 parent 7acabbc commit 2577aaf

2 files changed

Lines changed: 31 additions & 3 deletions

File tree

packages/studio-server/src/routes/render.test.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,37 @@ function createAdapter(
3333
return { adapter, rendersDir };
3434
}
3535

36-
function buildApp(spy: ReturnType<typeof vi.fn>): { app: Hono; cleanup: () => void } {
36+
function buildApp(spy: ReturnType<typeof vi.fn>): {
37+
app: Hono;
38+
rendersDir: string;
39+
cleanup: () => void;
40+
} {
3741
const { adapter, rendersDir } = createAdapter(spy);
3842
const app = new Hono();
3943
registerRenderRoutes(app, adapter);
40-
return { app, cleanup: () => rmSync(rendersDir, { recursive: true, force: true }) };
44+
return { app, rendersDir, cleanup: () => rmSync(rendersDir, { recursive: true, force: true }) };
4145
}
4246

47+
describe("GET /projects/:id/renders — stale sidecar status", () => {
48+
it("does not mark an existing output failed from stale metadata", async () => {
49+
const spy = vi.fn();
50+
const { app, rendersDir, cleanup } = buildApp(spy);
51+
try {
52+
writeFileSync(join(rendersDir, "retry.mp4"), "valid-output");
53+
writeFileSync(
54+
join(rendersDir, "retry.meta.json"),
55+
JSON.stringify({ status: "failed", error: "first attempt" }),
56+
);
57+
const res = await app.request("http://localhost/projects/demo/renders");
58+
expect(res.status).toBe(200);
59+
const body = await res.json();
60+
expect(body.renders).toEqual([expect.objectContaining({ id: "retry", status: "complete" })]);
61+
} finally {
62+
cleanup();
63+
}
64+
});
65+
});
66+
4367
describe("POST /projects/:id/render — outputResolution forwarding", () => {
4468
it("forwards a valid resolution preset to the adapter", async () => {
4569
const spy = vi.fn();

packages/studio-server/src/routes/render.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,11 @@ export function registerRenderRoutes(api: Hono, adapter: StudioApiAdapter): void
287287
if (existsSync(metaPath)) {
288288
try {
289289
const meta = JSON.parse(readFileSync(metaPath, "utf-8"));
290-
if (meta.status === "failed") status = "failed";
290+
// A stale failed sidecar can remain after a retry succeeds. An
291+
// existing output artifact is authoritative for the list view;
292+
// don't present a downloadable render as failed solely because
293+
// an earlier attempt left behind failed metadata.
294+
if (meta.status === "failed" && !existsSync(fp)) status = "failed";
291295
if (meta.durationMs) durationMs = meta.durationMs;
292296
} catch {
293297
/* ignore */

0 commit comments

Comments
 (0)