paperclipai/paperclip · warning
failed company transfer runs stranded in applying by a…
Error message
failed company transfer runs stranded in applying by a restart
What it means
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.
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.
Defensive patterns
Strategy: retry
Prevention
- 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.
When it happens
Trigger: 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.
Common situations: Rolling deploys landing during active imports; crashes mid-apply; aggressive container restart policies; host reboots during bulk company imports.
Related errors
- ACPX recovery identity does not match the persisted runtime…
- Could not open your browser automatically. Open this URL…
- credentials
- database-contract-unmet
- database_unavailable
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-08-18).
Data as JSON: /api/errors/c97d5768b9523854.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/app.ts:870
if (feedbackExportTimer) {
clearInterval(feedbackExportTimer);
feedbackExportTimer = null;
}
};
const flushPendingFeedbackExports = async () => {
if (feedbackExportShuttingDown) return;
try {
await opts.feedbackExportService?.flushPendingFeedbackTraces();
} catch (err) {
if (isDatabaseConnectionUnavailableError(err)) {
disableFeedbackExportFlushes();
logger.warn({ err }, "Disabling pending feedback export flushes because the database is unavailable");
return;
}
logger.error({ err }, "Failed to flush pending feedback exports");
}
};
feedbackExportTimer = opts.feedbackExportService
? setInterval(() => {
void flushPendingFeedbackExports();
}, FEEDBACK_EXPORT_FLUSH_INTERVAL_MS)
: null;
feedbackExportTimer?.unref?.();
if (opts.feedbackExportService) {
void flushPendingFeedbackExports();
}
// Abandoned chunked-import spool sweep: hourly (plus once at startup),
// deleting spool dirs whose transfer saw no activity for 24h and cancelling
// their still-open ledger runs. Same setInterval + unref + shutdown-clear
// shape as the feedback export flush above.
const importTransferSpoolRoot = resolveDefaultImportTransferSpoolRoot();
const sweepImportTransferSpools = () => {
sweepAbandonedImportTransferSpools(db, importTransferSpoolRoot)
.then((result) => {
if (result.swept > 0) {View on GitHub (pinned to 01ad858492)