{"record":{"id":"30dac2807e4590a1","repo":"schollz/croc","slug":"recipient-cancelled","errorCode":null,"errorMessage":"Recipient cancelled","messagePattern":"Recipient cancelled","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/src/protocol/client.ts","lineNumber":511,"sourceCode":"        request.CurrentFileChunkRanges,\n        data,\n        key,\n        (fileBytes) => {\n          totalTransferred = beforeFile + fileBytes;\n          callbacks.onProgress?.({\n            fileIndex,\n            fileCount: files.length,\n            fileName: prepared.name,\n            fileBytes,\n            fileSize: prepared.size,\n            totalBytes: totalTransferred,\n            totalSize,\n          });\n        },\n        signal,\n      );\n      const closed = await receiveControl(control, key);\n      if (closed.t === \"error\") throw new Error(closed.m || \"Recipient cancelled\");\n      if (closed.t !== \"close-sender\") {\n        throw new Error(`Expected recipient to close the file, got ${closed.t}`);\n      }\n      await sendControl(control, { t: \"close-recipient\" }, key);\n      callbacks.onFileComplete?.(prepared.name);\n    }\n  } catch (error) {\n    await reportPeerError(control, key, error);\n    throw error;\n  } finally {\n    closeAll(control, data);\n  }\n}\n\ntype ActiveReceive = {\n  file: OfferedFile;\n  sink: ReceiveSink;\n  received: Set<number>;","sourceCodeStart":493,"sourceCodeEnd":529,"githubUrl":"https://github.com/schollz/croc/blob/e25f1bdc04f07f094d50b0a1bf67e2563944b57a/web/src/protocol/client.ts#L493-L529","documentation":"Thrown by the sender after streaming a file when the next control message from the recipient is an 'error' message (with no text, the fallback 'Recipient cancelled' is used). The recipient explicitly reported a failure over the control channel via reportPeerError, so the sender surfaces it and tears the transfer down. The recipient's own error string, when present, is preserved in the message.","triggerScenarios":"The recipient aborts mid-file: user cancels, onOffer refusal, a DataReceiver read failure (invalid/duplicate/out-of-range chunk) that rejects receivePromise and triggers the recipient's catch -> reportPeerError, recipient hash verification fails (verifySink), or the recipient's storage sink throws (quota, write error).","commonSituations":"Recipient browser tab closed or AbortSignal fired during transfer; recipient disk/partition or File System Access handle revoked; corrupted chunk from a relay or mismatched key causing DataReceiver validation failures; recipient user clicks 'Decline' or 'Cancel' in the offer UI after data started.","solutions":["Read the error text: a non-empty message pinpoints the recipient-side failure; 'Recipient cancelled' with no text usually means the recipient aborted via signal or closed the page","Reproduce with the recipient's console open — the same error is thrown there first and reported over the wire","Check recipient storage availability (File System Access permission, disk space, private-mode restrictions)","If it happens reproducibly at the same byte offset, suspect data-channel corruption: test over a different relay/network and confirm both sides use the same transfer settings"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isPeerErrorMessage(e: unknown): e is Error {\n  return e instanceof Error && /Recipient cancelled/.test(e.message);\n}","tryCatchPattern":"try {\n  await sendFiles(opts);\n} catch (e) {\n  if (e instanceof Error && /Recipient cancelled/.test(e.message)) {\n    showStatus(\"The receiver stopped the transfer\"); // user-visible cancellation, not a bug\n    return;\n  }\n  throw e; // genuine failure\n}","preventionTips":["Treat recipient-reported errors as expected control flow and surface the forwarded message text to the sender's user","Keep an AbortSignal wired on both peers so cancellations produce clean AbortError/peer-error paths instead of socket teardown","Test the decline/cancel path explicitly in your UI so this error maps to a friendly state"],"tags":["protocol","peer-error","file-transfer","cancel"],"backgroundTag":null,"analyzedSha":"e25f1bdc04f07f094d50b0a1bf67e2563944b57a","analyzedAt":"2026-08-15T12:53:39.096Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}