From 076c2e577f6d74362859c6e731f5b506ab8a1b6a Mon Sep 17 00:00:00 2001 From: "soroush.asadi" Date: Sat, 6 Jun 2026 19:37:59 +0330 Subject: [PATCH] fix(render): resolve template id for render jobs + mock-fallback when no .aep MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit THE bug behind "AEPFilePath is required for real AE render": CreateJob inserted original_project_id = saved_project_id (VALUES $3,$3), so the claim looked for the render bundle at templates/{saved_project_id}/ — which never exists. The bundle lives at templates/{TEMPLATE_id}/. Now original_project_id is resolved from studio.saved_projects.original_project_id (the template the project was built from). (Direct-SQL test renders masked this by setting the template id explicitly.) Also harden the node-agent: Run() falls back to mock render when AEPFilePath is empty even if AE is installed (previously hard-errored), so a missing/un-promoted template degrades gracefully instead of failing the job. Co-Authored-By: Claude Opus 4.8 --- services/node-agent/internal/runner/runner.go | 9 ++++++++- services/render/internal/db/db.go | 6 +++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/services/node-agent/internal/runner/runner.go b/services/node-agent/internal/runner/runner.go index cb5e472..efdc26c 100644 --- a/services/node-agent/internal/runner/runner.go +++ b/services/node-agent/internal/runner/runner.go @@ -48,7 +48,14 @@ func Run(ctx context.Context, aePath, workDir string, job *Job, onProgress Progr } outputPath := filepath.Join(outputDir, "output.mp4") - if aePath == "" { + // Mock render when AE isn't installed (aePath empty) OR when this job has no + // template project to render (AEPFilePath empty — the template bundle wasn't + // uploaded/promoted yet). Mock drives progress+preview to completion so the job + // doesn't hard-fail; a real render requires both AE and a downloaded .aep. + if aePath == "" || job.AEPFilePath == "" { + if aePath != "" && job.AEPFilePath == "" { + log.Printf("[job %s] no template .aep available — falling back to mock render", job.JobID) + } return mockRender(ctx, job, outputPath, onProgress, onPreview) } return aeRender(ctx, aePath, job, outputPath, onProgress, onPreview) diff --git a/services/render/internal/db/db.go b/services/render/internal/db/db.go index 281feb6..d41b373 100644 --- a/services/render/internal/db/db.go +++ b/services/render/internal/db/db.go @@ -430,7 +430,11 @@ func (s *Store) CreateJob(ctx context.Context, userID, tenantID uuid.UUID, req * (tenant_id, user_id, saved_project_id, original_project_id, priority_queue, step, price_type, quality, resolution, r_height, frame_rate, is_60_fps, duration_sec, mode, tell_me_when_done, region) - VALUES ($1, $2, $3, $3, + VALUES ($1, $2, $3, + -- original_project_id = the TEMPLATE the saved project was created from + -- (the render bundle lives at templates/{original_project_id}/). Fall back + -- to the saved-project id only if the lookup is somehow null. + COALESCE((SELECT original_project_id FROM studio.saved_projects WHERE id = $3), $3), 'paid'::render_priority_queue, 'Queued'::render_step, $4::price_kind, $5::render_quality, $6, 1080, $7, COALESCE($8, FALSE), 0, 'FIX', $9, $10)