{"record":{"id":"f3ed9076add6ecc4","repo":"alyssaxuu/screenity","slug":"failed-to-create-video-project","errorCode":null,"errorMessage":"Failed to create video project","messagePattern":"Failed to create video project","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/pages/CloudRecorder/CloudRecorder.jsx","lineNumber":7892,"sourceCode":"              multiSceneCount: multiSceneCount || 0,\n            });\n          }\n        } else {\n          // Usually already resolved by the prefetch kicked off before mic\n          // acquisition; falls back to a fresh create if the prefetch saw a\n          // project in storage that has since been cleared.\n          videoId = await projectPrefetch;\n          if (!videoId) {\n            const now = new Date();\n            const options = { day: \"2-digit\", month: \"short\", year: \"numeric\" };\n            const startedAt = Date.now();\n            videoId = await createVideoProject({\n              title: `Untitled video - ${now.toLocaleString(\"en-GB\", options)}`,\n              instantMode: instantMode.current,\n            });\n            projectCreateMs = Date.now() - startedAt;\n          }\n          if (!videoId) throw new Error(\"Failed to create video project\");\n\n          if (multiMode) {\n            await chrome.storage.local.set({\n              multiProjectId: videoId,\n              multiSceneCount: 0,\n            });\n          }\n        }\n\n        await chrome.storage.local.set({ projectId: videoId });\n        // Fresh projects already carry hasRecordingSession, so only\n        // reused ones need the hint.\n        if (reusedProject) notifyRecordingStarted(videoId);\n        traceStep(\"apiProjectCreated\", {\n          projectCreateMs,\n          projectReused: reusedProject,\n        });\n        void emitUploadTelemetry(\"project_state_change\", {","sourceCodeStart":7874,"sourceCodeEnd":7910,"githubUrl":"https://github.com/alyssaxuu/screenity/blob/512606387b8d07dda5e63bb428bd063f0a2a3ed0/src/pages/CloudRecorder/CloudRecorder.jsx#L7874-L7910","documentation":"Thrown when neither storage (projectId/multiProjectId), the project prefetch, nor a fresh createVideoProject() call yields a video ID. It guards against continuing the recording pipeline without a backend project to attach scenes/media to.","triggerScenarios":"chrome.storage.local has no projectId and no multiProjectId, projectPrefetch resolves to a falsy value, and the fallback createVideoProject({title, instantMode}) returns null/undefined instead of an ID.","commonSituations":"createVideoProject silently swallowing an API error (auth expired, network down, backend 5xx) and returning null instead of throwing; prefetch raced with a storage clear and lost; user's account hit a project-creation limit.","solutions":["Log the response inside createVideoProject to see why it returns falsy (network error, non-2xx, missing id in body)","Check auth/session validity before starting recording; expired tokens commonly make the create call fail silently","Confirm the prefetch promise is not being .catch()'d to null elsewhere and hiding a real error","Retry the recording start; transient network failures to the project-create endpoint are the usual cause"],"exampleFix":"// before\nvideoId = await createVideoProject({ title, instantMode: instantMode.current });\nif (!videoId) throw new Error(\"Failed to create video project\");\n// after\nvideoId = await createVideoProject({ title, instantMode: instantMode.current });\nif (!videoId) {\n  const created = await createVideoProject({ title, instantMode: instantMode.current });\n  videoId = created?.id ?? created;\n}\nif (!videoId) throw new Error(\"Failed to create video project\");","handlingStrategy":"validation","validationCode":"const { projectId, multiProjectId } = await chrome.storage.local.get([\"projectId\", \"multiProjectId\"]);\nconst prefetchId = await projectPrefetch.catch(() => null);\nif (!projectId && !multiProjectId && !prefetchId && !(await isBackendReachable())) {\n  throw new Error(\"Cannot start: no project and backend unreachable\");\n}","typeGuard":"function hasVideoId(v) {\n  return typeof v === \"string\" && v.length > 0 || typeof v === \"number\" && Number.isFinite(v);\n}","tryCatchPattern":"try {\n  videoId = await createVideoProject({ title, instantMode });\n} catch (err) {\n  sendRecordingError(\"Project create failed: \" + err.message);\n}\nif (!hasVideoId(videoId)) {\n  videoId = await createVideoProject({ title, instantMode }); // one retry\n}\nif (!hasVideoId(videoId)) throw new Error(\"Failed to create video project\");","preventionTips":["Make createVideoProject throw on API errors instead of silently returning null","Check auth validity and network reachability before recording start","Log the create response body so a falsy return is always diagnosable","Treat projectPrefetch rejections as errors, not silently swallowed nulls"],"tags":["api","backend","project-creation","chrome-extension"],"backgroundTag":"project-create-returned-null","analyzedSha":"512606387b8d07dda5e63bb428bd063f0a2a3ed0","analyzedAt":"2026-09-02T20:59:09.419Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}