{"record":{"id":"c97d5768b9523854","repo":"paperclipai/paperclip","slug":"failed-company-transfer-runs-stranded-in-applying","errorCode":null,"errorMessage":"failed company transfer runs stranded in applying by a restart","messagePattern":"failed company transfer runs stranded in applying by a restart","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"server/src/app.ts","lineNumber":849,"sourceCode":"      .catch((err) => {\n        logger.error({ err }, \"abandoned company import transfer spool sweep failed\");\n      });\n  };\n  let importTransferSweepTimer: ReturnType<typeof setInterval> | null = setInterval(\n    sweepImportTransferSpools,\n    IMPORT_TRANSFER_SPOOL_SWEEP_INTERVAL_MS,\n  );\n  importTransferSweepTimer.unref?.();\n  // Startup only (never on the hourly interval — that would kill live\n  // applies): apply jobs are in-memory in this single process, so any run\n  // still \"applying\" now was interrupted by the previous shutdown and would\n  // otherwise 409 every retry forever. Fail those stranded runs — their\n  // spooled parts stay reusable — then run the normal sweep once.\n  void companyTransferRunService\n    .recoverStrandedApplyingRuns(db)\n    .then((recovered) => {\n      if (recovered.length > 0) {\n        logger.warn(\n          { count: recovered.length, runIds: recovered },\n          \"failed company transfer runs stranded in applying by a restart\",\n        );\n      }\n    })\n    .catch((err) => {\n      logger.error({ err }, \"stranded company transfer apply recovery failed\");\n    })\n    .finally(() => {\n      sweepImportTransferSpools();\n    });\n  void toolDispatcher.initialize().catch((err) => {\n    logger.error({ err }, \"Failed to initialize plugin tool dispatcher\");\n  });\n  const devWatcher = createPluginDevWatcher(\n    lifecycle,\n    async (pluginId) => (await pluginRegistry.getById(pluginId))?.packagePath ?? null,\n  );","sourceCodeStart":831,"sourceCodeEnd":867,"githubUrl":"https://github.com/paperclipai/paperclip/blob/a7e689b3c35347b529cb9f54c9b9a8575a3dcab6/server/src/app.ts#L831-L867","documentation":"Company-transfer apply jobs are in-memory in the single server process. At startup, recoverStrandedApplyingRuns fails any run still marked 'applying' — those were interrupted by the previous shutdown and would otherwise 409 on every retry forever. Their spooled transfer parts remain reusable, and this warning lists the recovered run ids.","triggerScenarios":"The server process restarted (deploy, crash, OOM kill, container restart) while a company import transfer was in its 'applying' phase; on next boot those runs are failed and listed in the warn.","commonSituations":"Rolling deploys landing during active imports; crashes mid-apply; aggressive container restart policies; host reboots during bulk company imports.","solutions":["Retry the company transfers whose runIds appear in the warning — spooled parts make the retry cheap.","Before planned restarts, let in-flight transfers finish (maintenance window / drain) to avoid stranding.","If the restart was unexpected, check the previous process's logs for the crash cause.","Do not hand-edit the runs' DB state — recovery already failed them cleanly."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Quiesce company transfers (drain/finish) before planned restarts and deploys.","Keep the transfer spool directory on durable storage so retried runs reuse parts.","Alert on this startup warn and retry the listed runIds — recovery already failed them cleanly.","Repeated strandings indicate a crash loop; investigate the shutdown cause, not the warn."],"tags":["company-transfer","import","recovery","restart","startup"],"backgroundTag":"interrupted-job-recovery","analyzedSha":"a7e689b3c35347b529cb9f54c9b9a8575a3dcab6","analyzedAt":"2026-08-18T22:49:45.177Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}