{"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":870,"sourceCode":"    if (feedbackExportTimer) {\n      clearInterval(feedbackExportTimer);\n      feedbackExportTimer = null;\n    }\n  };\n  const flushPendingFeedbackExports = async () => {\n    if (feedbackExportShuttingDown) return;\n    try {\n      await opts.feedbackExportService?.flushPendingFeedbackTraces();\n    } catch (err) {\n      if (isDatabaseConnectionUnavailableError(err)) {\n        disableFeedbackExportFlushes();\n        logger.warn({ err }, \"Disabling pending feedback export flushes because the database is unavailable\");\n        return;\n      }\n      logger.error({ err }, \"Failed to flush pending feedback exports\");\n    }\n  };\n\n  feedbackExportTimer = opts.feedbackExportService\n    ? setInterval(() => {\n      void flushPendingFeedbackExports();\n    }, FEEDBACK_EXPORT_FLUSH_INTERVAL_MS)\n    : null;\n  feedbackExportTimer?.unref?.();\n  if (opts.feedbackExportService) {\n    void flushPendingFeedbackExports();\n  }\n  // Abandoned chunked-import spool sweep: hourly (plus once at startup),\n  // deleting spool dirs whose transfer saw no activity for 24h and cancelling\n  // their still-open ledger runs. Same setInterval + unref + shutdown-clear\n  // shape as the feedback export flush above.\n  const importTransferSpoolRoot = resolveDefaultImportTransferSpoolRoot();\n  const sweepImportTransferSpools = () => {\n    sweepAbandonedImportTransferSpools(db, importTransferSpoolRoot)\n      .then((result) => {\n        if (result.swept > 0) {","sourceCodeStart":852,"sourceCodeEnd":888,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/app.ts#L852-L888","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":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-08-18T22:49:45.177Z","contentChangedAt":"2026-08-18T22:49:45.177Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}