{"record":{"id":"e33fc7a89a86cefd","repo":"paperclipai/paperclip","slug":"the-stop-was-requested-but-work-is-still-stopping-try-stop","errorCode":null,"errorMessage":"The stop was requested, but work is still stopping. Try Stop again if it continues.","messagePattern":"The stop was requested, but work is still stopping\\. Try Stop again if it continues\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ui/src/lib/wait-for-stopped-runs.ts","lineNumber":56,"sourceCode":"      .filter((run) => {\n        if (LIVE_STATUSES.has(run.status)) return true;\n        const adapterCancellation = run.resultJson?.executionCancellation;\n        if (adapterCancellation && typeof adapterCancellation === \"object\"\n          && \"state\" in adapterCancellation && adapterCancellation.state !== \"acknowledged\") return true;\n        if (!(\"runtimeMode\" in run) || run.runtimeMode !== \"native\" || run.status !== \"cancelled\")\n          return false;\n        const cancellation = run.resultJson?.nativeCancellation;\n        return (\n          !cancellation ||\n          typeof cancellation !== \"object\" ||\n          !(\"dispatchState\" in cancellation) ||\n          cancellation.dispatchState !== \"acknowledged\"\n        );\n      })\n      .map((run) => run.id);\n    if (remaining.length === 0) return;\n    if (Date.now() >= deadline) {\n      throw new Error(\n        \"The stop was requested, but work is still stopping. Try Stop again if it continues.\",\n      );\n    }\n    await new Promise((resolve) =>\n      setTimeout(resolve, options.intervalMs ?? 500),\n    );\n  }\n}\n","sourceCodeStart":38,"sourceCodeEnd":65,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/ui/src/lib/wait-for-stopped-runs.ts#L38-L65","documentation":"After filtering, if some runs still report a non-acknowledged cancellation dispatch state and the deadline has passed, `waitForStoppedRuns` throws this message: the stop was requested but work is demonstrably still stopping/unstopped at timeout. Unlike 518 this is the deliberate deadline expiry path, not a wrapped inner failure.","triggerScenarios":"Poll loop reaches `Date.now() >= deadline` while `remaining` is non-empty — runs whose cancellation.dispatchState never became 'acknowledged' within the deadline.","commonSituations":"Long-running agent runs that take longer than the deadline to cancel; backend backlog in processing cancellation; stale poll responses making runs look unacknowledged.","solutions":["Wait briefly and try Stop again as the message suggests; check the Activity/run log for dispatch state transitions.","Increase `deadlineMs` (or options) at call sites where long-running runs are common.","Investigate the server-side cancellation path if dispatch state stays unacknowledged indefinitely."],"exampleFix":"// before\nawait waitForStoppedRuns(ids, { deadlineMs: 8000 });\n// after\nawait waitForStoppedRuns(ids, { deadlineMs: 30000, intervalMs: 1000 });","handlingStrategy":"retry","validationCode":"const states = await fetchRunStates(ids); const pending = states.filter((r) => r.cancellation?.dispatchState !== 'acknowledged'); if (pending.length === 0) return;","typeGuard":"const isAcknowledged = (r: RunState): boolean => r.cancellation?.dispatchState === 'acknowledged';","tryCatchPattern":"for (let i = 0; i < 2; i++) { try { await waitForStoppedRuns(ids); break; } catch { if (i === 1) showToast('Work still stopping — check Activity'); await sleep(2000); } }","preventionTips":["Retry Stop after a short wait instead of immediately re-invoking.","Set deadlines proportional to expected run duration.","Monitor server cancellation acknowledgement latency if this recurs."],"tags":["timeout","cancellation","polling"],"backgroundTag":"request-timeout","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}