{"record":{"id":"54d328738ea162f9","repo":"different-ai/openwork","slug":"size-mismatch","errorCode":"size-mismatch","errorMessage":"Downloaded data changed while it was being saved.","messagePattern":"Downloaded data changed while it was being saved\\.","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/desktop/electron/binary-transfer.mjs","lineNumber":333,"sourceCode":"    // symlink), and prove by device and inode that the created file resides\n    // inside the authorized root before a single byte is written to it.\n    await resolveAuthorizedPath(input?.destinationPath, options?.authorizedRoots);\n    try {\n      destinationFile = await open(destinationPath, \"wx\");\n    } catch (error) {\n      if (error?.code === \"EEXIST\") {\n        throw transferError(\"Download destination already exists.\", \"destination-exists\");\n      }\n      throw error;\n    }\n    await verifyOpenFileWithinRoot(destinationFile, destinationPath, destination.rootRealPath, \"Download destination\");\n    const buffer = Buffer.allocUnsafe(1024 * 1024);\n    let position = 0;\n    while (position < bytes) {\n      signal?.throwIfAborted();\n      const { bytesRead } = await stagingFile.read(buffer, 0, Math.min(buffer.length, bytes - position), position);\n      if (bytesRead === 0) {\n        throw transferError(\"Downloaded data changed while it was being saved.\", \"size-mismatch\");\n      }\n      await writeAll(destinationFile, buffer.subarray(0, bytesRead));\n      position += bytesRead;\n    }\n    await destinationFile.sync();\n    await destinationFile.close();\n    destinationFile = undefined;\n    return { ...responseMetadata(response), path: destinationPath, bytes };\n  } catch (error) {\n    // Cleanup goes through the verified handle, never through the path, so a\n    // swapped parent cannot turn cleanup into an out-of-workspace deletion.\n    if (destinationFile) {\n      await destinationFile.truncate(0).catch(() => undefined);\n      await destinationFile.close().catch(() => undefined);\n    }\n    throw error;\n  } finally {\n    await stagingFile?.close().catch(() => undefined);","sourceCodeStart":315,"sourceCodeEnd":351,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/apps/desktop/electron/binary-transfer.mjs#L315-L351","documentation":"While copying bytes from the staging file to the final destination, downloadBinaryToPath throws 'size-mismatch' if a read returns 0 bytes before `bytes` (the count just downloaded) have been copied. This means the staging file shrank or became unreadable between download and promotion — the downloaded data changed while it was being saved.","triggerScenarios":"During the staging-to-destination copy loop, stagingFile.read returns bytesRead === 0 while position < bytes, i.e. the staging file is shorter than the byte count recorded during streaming.","commonSituations":"Another process/user truncating or deleting the staging file mid-transfer (cleanup daemon, antivirus, temp-file sweeper); disk-full or fs errors surfacing as short reads; racing downloads sharing a temp directory.","solutions":["Simply retry the whole download — this is detected corruption, and a fresh run to a fresh staging file is the fix.","Ensure nothing purges the staging directory during downloads (antivirus exclusions, tmpwatch/systemd-tmpfiles settings).","Check free disk space on the staging volume; ENOSPC can truncate files.","Avoid sharing one staging/temp directory across concurrent downloads."],"exampleFix":"// before\nawait downloadBinaryToPath({ url, destinationPath });\n// after\nimport { transferErrorShape } from \"./binary-transfer.mjs\";\ntry {\n  await downloadBinaryToPath({ url, destinationPath });\n} catch (e) {\n  if (e.code === \"size-mismatch\") await downloadBinaryToPath({ url, destinationPath }); // one clean retry\n  else throw e;\n}","handlingStrategy":"retry","validationCode":"import { statfs } from \"node:fs/promises\";\nconst { bavail, bsize } = await statfs(path.dirname(destinationPath));\nif (bavail * bsize < expectedBytes * 2) throw new Error(\"Insufficient free space for staging plus destination\");","typeGuard":null,"tryCatchPattern":"try {\n  await downloadBinaryToPath({ url, destinationPath });\n} catch (e) {\n  if (e?.code === \"size-mismatch\") {\n    // staging file was truncated mid-copy: one clean retry on a fresh staging file\n    return downloadBinaryToPath({ url, destinationPath });\n  }\n  throw e;\n}","preventionTips":["Exclude the staging/tmp directory from cleanup daemons and antivirus scanners.","Keep ample free disk space on the staging volume.","Don't share one staging directory across concurrent downloads.","Retry the whole download once on size-mismatch — it indicates detected corruption."],"tags":["download","filesystem","integrity","race-condition"],"backgroundTag":"file-changed-during-transfer","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}