{"record":{"id":"43d17da8c83284f9","repo":"Foundry376/Mailspring","slug":"the-mbox-file-is-shorter-than-the-manifest-mboxb","errorCode":null,"errorMessage":"The mbox file is shorter than the ${manifest.mboxBytes} bytes already exported — it was moved or modified while the export was running.","messagePattern":"The mbox file is shorter than the (.+?) bytes already exported — it was moved or modified while the export was running\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/src/services/mbox-utils.ts","lineNumber":242,"sourceCode":"      if (file <= manifest.lastConsumedName) {\n        await fs.promises.rm(path.join(stagingDir, file), { force: true });\n      }\n    }\n    files = files.filter((f) => f > manifest.lastConsumedName);\n  }\n\n  const maxCount = exportedCount == null ? files.length : exportedCount - manifest.consumedCount;\n  const batch = files.slice(0, Math.max(0, maxCount));\n\n  // Recovery: reconcile the mbox with the manifest before appending.\n  let mboxSize = 0;\n  try {\n    mboxSize = (await fs.promises.stat(mboxPath)).size;\n  } catch (err) {\n    // no mbox yet\n  }\n  if (mboxSize < manifest.mboxBytes) {\n    throw new Error(\n      `The mbox file is shorter than the ${manifest.mboxBytes} bytes already exported — it was moved or modified while the export was running.`\n    );\n  }\n\n  // Read-write (not append) mode with explicitly positioned writes: append\n  // mode would be simpler, but on Windows Node opens 'a' handles without\n  // write-data access and the recovery truncate below can fail on them, and\n  // O_APPEND positioning after ftruncate is exactly the kind of cross-\n  // platform subtlety this file shouldn't depend on.\n  const fh = await fs.promises.open(mboxPath, fs.constants.O_RDWR | fs.constants.O_CREAT);\n  let offset = manifest.mboxBytes;\n  let consumedCount = manifest.consumedCount;\n  let lastConsumedName = manifest.lastConsumedName;\n  try {\n    if (mboxSize > manifest.mboxBytes) {\n      // torn append from a crash (or a pre-existing file being overwritten,\n      // when the manifest is fresh) — drop the unrecorded bytes\n      await fh.truncate(manifest.mboxBytes);","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/Foundry376/Mailspring/blob/648c685d602ece6bb00c22534b8734de6ac644b3/app/src/services/mbox-utils.ts#L224-L260","documentation":"Reconciliation guard in appendStagedMessages: before appending staged messages, the on-disk mbox size is compared against manifest.mboxBytes (bytes already exported). A smaller file means the mbox was moved, truncated, or replaced mid-export, so appending would silently produce a corrupt archive combining mismatched content.","triggerScenarios":"Thrown at app/src/services/mbox-utils.ts:242 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Restore the mbox from backup if it was accidentally moved or truncated","Delete the mbox and staging directory and restart the export to regenerate both","Ensure no other process (e.g. another client or sync tool) is writing to the mbox during export"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"648c685d602ece6bb00c22534b8734de6ac644b3","analyzedAt":"2026-09-03T02:00:24.311Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T07:17:11.731Z"}