{"record":{"id":"c28e0d2cf4fa1447","repo":"stablyai/orca","slug":"review-file-has-expired-create-a-new-one-before-s","errorCode":null,"errorMessage":"review file has expired; create a new one before sending","messagePattern":"review file has expired; create a new one before sending","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/main/ipc/diagnostics.ts","lineNumber":116,"sourceCode":"    bytes: bundle.bytes,\n    spanCount: bundle.spanCount\n  }\n}\n\nfunction getPendingBundleForUpload(bundleSubmissionId: unknown): {\n  readonly bundle: CollectedBundle\n  readonly payload: string\n} {\n  if (\n    typeof bundleSubmissionId !== 'string' ||\n    !/^[A-Za-z0-9_-]{16,64}$/.test(bundleSubmissionId)\n  ) {\n    throw new Error('bundleSubmissionId has invalid format')\n  }\n  prunePendingBundles()\n  const pending = pendingBundles.get(bundleSubmissionId)\n  if (!pending) {\n    throw new Error('review file has expired; create a new one before sending')\n  }\n  if (!pending.previewOpened) {\n    throw new Error('open the review file before sending')\n  }\n  // Why: the preview file is user-editable once opened in the OS. Upload only\n  // the redacted bytes main collected and retained before preview.\n  return { bundle: pending.bundle, payload: pending.bundle.payload }\n}\n\nfunction getPendingPreviewFilePath(bundleSubmissionId: unknown): string {\n  if (\n    typeof bundleSubmissionId !== 'string' ||\n    !/^[A-Za-z0-9_-]{16,64}$/.test(bundleSubmissionId)\n  ) {\n    throw new Error('bundleSubmissionId has invalid format')\n  }\n  prunePendingBundles()\n  const pending = pendingBundles.get(bundleSubmissionId)","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/ipc/diagnostics.ts#L98-L134","documentation":"Thrown by getPendingBundleForUpload when bundleSubmissionId passes format validation but is not present in the pendingBundles map (after pruning). Pending bundles are short-lived in-memory entries created when a diagnostics bundle/review file is generated; they expire after a TTL or are discarded on app exit, so a stale or post-restart ID is gone.","triggerScenarios":"Calling the send/upload IPC with a bundleSubmissionId from a previous app session, after the prune TTL elapsed, or after the bundle was already discarded. The format regex passed (so the ID is well-formed) but the map lookup missed.","commonSituations":"App was restarted between creating the review file and sending it; the user waited longer than the bundle TTL; the bundle was discarded by memory pressure/pruning; an old submission ID was reused after a reload.","solutions":["Create a new review/diagnostics bundle to get a fresh bundleSubmissionId, then send within the same session.","Send the review file promptly after creating it, before the TTL expires.","Avoid app restarts between create and send; if restarted, always regenerate the bundle."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"function hasPendingBundle(bundleSubmissionId: string): boolean {\n  prunePendingBundles()\n  return pendingBundles.has(bundleSubmissionId)\n}","typeGuard":"function isPendingBundleFresh(id: string, map: Map<string, unknown>): boolean {\n  return map.has(id)\n}","tryCatchPattern":"try {\n  return getPendingBundleForUpload(id)\n} catch (error) {\n  if (error instanceof Error && /expired; create a new one/.test(error.message)) {\n    const fresh = await createReviewBundle(...)\n    return getPendingBundleForUpload(fresh.bundleSubmissionId)\n  }\n  throw error\n}","preventionTips":["Send review files in the same session that created them.","Send promptly after creation, within the bundle TTL.","On app restart, always regenerate bundles rather than reusing stale IDs."],"tags":["diagnostics","review-file","ipc","state","expiry"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}