{"record":{"id":"bb84cdbdc76c4470","repo":"stablyai/orca","slug":"invalid-local-log-tail-subscription-id","errorCode":null,"errorMessage":"Invalid local log tail subscription id","messagePattern":"Invalid local log tail subscription id","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ipc/local-log-tail.ts","lineNumber":45,"sourceCode":"  if (!subscription) {\n    return\n  }\n  tailWatches.delete(key)\n  subscription.watcher.close()\n}\n\nfunction closeSenderWatches(senderId: number): void {\n  senderCleanupRegistered.delete(senderId)\n  for (const [key, subscription] of tailWatches) {\n    if (subscription.senderId === senderId) {\n      closeWatch(key)\n    }\n  }\n}\n\nfunction validateSubscriptionId(value: unknown): string {\n  if (typeof value !== 'string' || value.length === 0 || value.length > 200) {\n    throw new Error('Invalid local log tail subscription id')\n  }\n  return value\n}\n\nfunction registerSenderCleanup(sender: WebContents): void {\n  if (senderCleanupRegistered.has(sender.id)) {\n    return\n  }\n  senderCleanupRegistered.add(sender.id)\n  sender.once('destroyed', () => closeSenderWatches(sender.id))\n}\n\nexport function registerLocalLogTailHandlers(store: Store): void {\n  ipcMain.handle(\n    'fs:readLocalLogTail',\n    async (_event, args: LocalLogTailReadArgs): Promise<LocalLogTailReadResult> => {\n      const filePath = await resolveAuthorizedPath(args.filePath, store)\n      return readLocalLogTailRange(filePath, args.fromByteOffset, args.expectedIdentity)","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/ipc/local-log-tail.ts#L27-L63","documentation":"Thrown by validateSubscriptionId when the local-log-tail subscription id is not a string, is empty, or exceeds 200 characters. The subscription id keys into tailWatches (a Map of active log tail watchers keyed by sender), so it must be a bounded, non-empty string to prevent map pollution and unbounded key growth.","triggerScenarios":"Calling a local-log-tail IPC subscribe/unsubscribe method with a missing, empty, non-string, or >200-char id. Reusing stale subscription ids after the sender was destroyed, or generating ids without a length cap.","commonSituations":"Renderer generates a uuid per subscription but a code path sends undefined. A bug causes the same empty id to collide across subscriptions. An adversarial or corrupted payload supplies an oversized id.","solutions":["Generate a unique, bounded-length id (e.g. crypto.randomUUID()) for each subscription and pass it as a string.","Unsubscribe using the same id when the tail is no longer needed, so the watch is closed in closeSenderWatches.","Never reuse or omit the id; track active ids in renderer state."],"exampleFix":"// before\nawait ipc.call('localLogTail:subscribe', { id: maybeId ?? '', path })\n\n// after\nconst id = crypto.randomUUID()\nawait ipc.call('localLogTail:subscribe', { id, path })","handlingStrategy":"validation","validationCode":"function validSubId(value: unknown): string {\n  if (typeof value !== 'string' || value.length === 0 || value.length > 200) {\n    throw new Error('Invalid subscription id')\n  }\n  return value\n}","typeGuard":"function isSubscriptionId(value: unknown): value is string {\n  return typeof value === 'string' && value.length > 0 && value.length <= 200\n}","tryCatchPattern":null,"preventionTips":["Generate a fresh crypto.randomUUID() for each log tail subscription.","Always unsubscribe with the same id to release the watch.","Track active subscription ids in renderer state to avoid leaks."],"tags":["validation","log-tail","subscription","ipc","resource-management"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}