{"record":{"id":"39e89d5d768ae221","repo":"alyssaxuu/screenity","slug":"invalid-reuse-object-must-have-both-videoid-and-m","errorCode":null,"errorMessage":"Invalid reuse object: must have both videoId and mediaId","messagePattern":"Invalid reuse object: must have both videoId and mediaId","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/pages/CloudRecorder/bunnyTusUploader.js","lineNumber":869,"sourceCode":"        projectId,\n        sceneId,\n        type,\n        width,\n        height,\n      });\n      this.fingerprint = fingerprint;\n\n      const resumeJournal = await this.getResumeJournal({\n        projectId,\n        sceneId,\n        type,\n        fingerprint,\n        reuse,\n      });\n\n      if (reuse) {\n        if (!reuse.videoId || !reuse.mediaId) {\n          throw new Error(\n            \"Invalid reuse object: must have both videoId and mediaId\",\n          );\n        }\n        this.videoId = reuse.videoId;\n        this.mediaId = reuse.mediaId;\n      } else if (resumeJournal?.videoId && resumeJournal?.mediaId) {\n        this.initializedFromResume = true;\n        this.videoId = resumeJournal.videoId;\n        this.mediaId = resumeJournal.mediaId;\n        this.uploadUrl = resumeJournal.uploadUrl || null;\n        this.offset = resumeJournal.offset || 0;\n        this.totalBytes = resumeJournal.totalBytes || 0;\n        this.journalKey =\n          resumeJournal.key || this.journalKey || this.getJournalKey(this.mediaId);\n        this.journalLookupKey = resumeJournal.lookupKey || this.journalLookupKey;\n        if (!this.sessionId && resumeJournal.sessionId) {\n          this.sessionId = resumeJournal.sessionId;\n        }","sourceCodeStart":851,"sourceCodeEnd":887,"githubUrl":"https://github.com/alyssaxuu/screenity/blob/512606387b8d07dda5e63bb428bd063f0a2a3ed0/src/pages/CloudRecorder/bunnyTusUploader.js#L851-L887","documentation":"uploader.initialize() accepts an optional `reuse` object so the caller can attach the upload to an already-created Bunny video instead of creating a new one. When `reuse` is truthy but is missing either `videoId` or `mediaId` (the two identifiers the uploader needs to target the existing video), the constructor-time contract is broken and initialize() throws immediately before doing any network work. This is a caller-supplied-input validation error, not a network or auth failure.","triggerScenarios":"Calling initialize({..., reuse}) where reuse is truthy but reuse.videoId or reuse.mediaId is undefined/null/empty string — e.g. reuse was built from an API response field that was absent, or a partially-hydrated object was passed in.","commonSituations":"Passing a stored video-map entry where only one of the two IDs survived serialization; destructuring a server response where the API changed shape and only videoId came back; passing `{}` or a truthy-but-incomplete placeholder to force reuse semantics.","solutions":["Fix the caller to pass both reuse.videoId and reuse.mediaId (non-empty strings) whenever reuse is provided.","If reuse cannot be fully populated, omit the reuse property entirely so initialize() falls back to journal/video-map lookup or creates a fresh Bunny video.","Inspect where the reuse object was built and log it; likely one field is undefined because the upstream API/storage shape changed."],"exampleFix":"// before\nawait uploader.initialize({ projectId, sceneId, type, reuse: videoInfo });\n// after\nconst reuse = videoInfo?.videoId && videoInfo?.mediaId ? { videoId: videoInfo.videoId, mediaId: videoInfo.mediaId } : undefined;\nawait uploader.initialize({ projectId, sceneId, type, reuse });","handlingStrategy":"validation","validationCode":"if (reuse && !(typeof reuse.videoId === 'string' && reuse.videoId && typeof reuse.mediaId === 'string' && reuse.mediaId)) {\n  throw new TypeError('reuse must include both videoId and mediaId, or be omitted');\n}","typeGuard":"function isValidReuse(reuse) {\n  return reuse == null || (typeof reuse.videoId === 'string' && reuse.videoId.length > 0 && typeof reuse.mediaId === 'string' && reuse.mediaId.length > 0);\n}","tryCatchPattern":"try {\n  await uploader.initialize({ projectId, sceneId, type, reuse });\n} catch (err) {\n  if (String(err?.message).includes('Invalid reuse object')) {\n    // fall back to fresh/journal init\n    await uploader.initialize({ projectId, sceneId, type });\n  } else throw err;\n}","preventionTips":["Only pass `reuse` when both IDs are known non-empty; otherwise omit the key.","Validate the source of the reuse object (API response/storage) at its construction site.","Add a unit test covering the reuse-partial-fields case.","Log the reuse object before calling initialize to catch shape regressions early."],"tags":["validation","argument-error","cloud-recorder"],"backgroundTag":"invalid-argument-value","analyzedSha":"512606387b8d07dda5e63bb428bd063f0a2a3ed0","analyzedAt":"2026-09-02T20:59:09.419Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}