{"record":{"id":"8d7b1cb9a85b5656","repo":"stablyai/orca","slug":"too-many-pending-terminal-history-seed-transfers","errorCode":null,"errorMessage":"Too many pending terminal history seed transfers","messagePattern":"Too many pending terminal history seed transfers","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/daemon/terminal-history-seed-transfer-registry.ts","lineNumber":33,"sourceCode":"  utf8Bytes: number\n  hash: ReturnType<typeof createHash>\n  finished: boolean\n  timer: ReturnType<typeof setTimeout>\n}\n\nexport class TerminalHistorySeedTransferRegistry {\n  private transfers = new Map<string, Transfer>()\n  private retainedBytes = 0\n\n  constructor(\n    private readonly maxRetainedBytes = TERMINAL_HISTORY_CHECKPOINT_MAX_BYTES,\n    private readonly transferTtlMs = TRANSFER_TTL_MS\n  ) {}\n\n  start(ownerId: string, manifest: TerminalHistorySeedTransferManifest): string {\n    this.validateManifest(manifest)\n    if (this.transfers.size >= MAX_TRANSFERS) {\n      throw new Error('Too many pending terminal history seed transfers')\n    }\n    const transferId = randomUUID()\n    const timer = setTimeout(() => this.delete(transferId), this.transferTtlMs)\n    timer.unref()\n    this.transfers.set(transferId, {\n      ownerId,\n      manifest: { ...manifest },\n      chunks: [],\n      codeUnits: 0,\n      utf8Bytes: 0,\n      hash: createHash('sha256'),\n      finished: false,\n      timer\n    })\n    return transferId\n  }\n\n  append(ownerId: string, transferId: string, index: number, data: string): void {","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/daemon/terminal-history-seed-transfer-registry.ts#L15-L51","documentation":"Thrown by TerminalHistorySeedTransferRegistry.start when the number of in-flight transfers has reached MAX_TRANSFERS (8). Each transfer holds chunks in memory until finish/take or a 30s TTL, so the registry caps concurrency to bound retained bytes. Starting a ninth transfer is refused.","triggerScenarios":"start() called while transfers.size >= 8, i.e., 8 transfers are already pending (not yet finished, taken, aborted, or expired).","commonSituations":"Bulk-restoring many terminal sessions at once (e.g., after a crash restoring 9+ tabs) each starting a seed transfer; transfers leaked because finish/take was never called and the 30s TTL has not yet elapsed; a client bug opening transfers without completing them.","solutions":["Complete (finish + take) or abort existing transfers before starting new ones; do not let transfers leak.","Serialize seed transfers across sessions so you never exceed 8 in flight.","Wait for the 30s TTL to reap stale transfers, then retry start.","Call clearOwner(clientId) when a client disconnects to reclaim its transfers."],"exampleFix":"// before: open a transfer per tab without bounding\nfor (const tab of tabs) {\n  const id = registry.start(clientId, metrics)\n}\n\n// after: bound concurrency and complete each before the next\nfor (const batch of chunks(tabs, 8)) {\n  const ids = batch.map(t => registry.start(clientId, measure(t)))\n  // append + finish + take each, then proceed\n}","handlingStrategy":"retry","validationCode":"// Bound in-flight transfers before starting a new one (registry max is 8)\nif (pendingTransferCount >= 8) {\n  // wait for some to finish/expire, or serialize\n}","typeGuard":"function isTooManySeedTransfers(e: unknown): boolean {\n  return e instanceof Error && e.message === 'Too many pending terminal history seed transfers'\n}","tryCatchPattern":"try {\n  return registry.start(ownerId, manifest)\n} catch (e) {\n  if (e instanceof Error && e.message === 'Too many pending terminal history seed transfers') {\n    await waitForTransferSlot(registry)  // complete/abort one, or wait ~TTL\n    return registry.start(ownerId, manifest)\n  }\n  throw e\n}","preventionTips":["Complete (finish + take) or abort transfers promptly; do not leak them.","Serialize seed transfers across sessions to stay under the cap of 8.","Call clearOwner on client disconnect to reclaim its transfers."],"tags":["history","seed-transfer","limits","concurrency"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}