{"record":{"id":"2e0b4c09b588c948","repo":"paperclipai/paperclip","slug":"interruption-is-unavailable","errorCode":null,"errorMessage":"interruption is unavailable","messagePattern":"interruption is unavailable","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/src/backends/harness-driver-backend.ts","lineNumber":688,"sourceCode":"      this.#rethrowProtocolIntegrity(error);\n      throw error;\n    }\n  }\n\n  steer(input: {\n    turnId: string;\n    message: { role: \"user\"; text: string };\n    correlationId?: string;\n  }) {\n    this.#assertProtocolIntegrity();\n    if (this.#session.steer === undefined)\n      throw new Error(\"steering is unavailable\");\n    return this.#withProtocolIntegrity(() => this.#session.steer!(input));\n  }\n\n  interrupt(input: { turnId?: string; reason?: string }) {\n    if (this.#session.interrupt === undefined)\n      throw new Error(\"interruption is unavailable\");\n    return this.#session.interrupt(input);\n  }\n\n  cancel(input: { reason: string; signal: AbortSignal }) {\n    if (input.signal.aborted) {\n      throw (\n        input.signal.reason ?? new Error(\"native session cancellation aborted\")\n      );\n    }\n    // This flag is the adapter's synchronous publication boundary. Provider\n    // interruption happens afterward as passive cleanup, so a slow or broken\n    // transport cannot synthesize or publish new accepted output for the turn.\n    this.#explicitlyCancelled = true;\n    const interrupt = this.#session.interrupt;\n    return {\n      cleanup:\n        interrupt === undefined\n          ? Promise.resolve()","sourceCodeStart":670,"sourceCodeEnd":706,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/paperclip-runner/src/backends/harness-driver-backend.ts#L670-L706","documentation":"interrupt forwards an interrupt request to the HarnessSession's optional interrupt capability. If the driver does not implement interrupt (this.#session.interrupt === undefined), the backend throws \"interruption is unavailable\" because it cannot abort the in-flight turn through the protocol.","triggerScenarios":"Calling interrupt() on a session whose driver lacks an interrupt implementation; attempting to cancel a turn on a driver that only supports full session cancel via cancel().","commonSituations":"Stop button in the UI targeting an agent adapter without turn-level interruption; older driver builds predating the interrupt protocol method; drivers that only support process-level cancellation.","solutions":["Use the backend's cancel() path (AbortSignal-based) instead of turn-level interrupt when interrupt is unsupported","Upgrade the driver/adapter to one implementing interrupt","Disable or hide turn-level stop controls for agents that report no interrupt capability","Feature-detect interrupt support before offering it"],"exampleFix":"// before\nbackend.interrupt({ turnId, reason: 'user-cancel' });\n// after\nif (!backend.canInterrupt()) {\n  abortController.abort(); // drives cancel(signal) path\n} else {\n  backend.interrupt({ turnId, reason: 'user-cancel' });\n}","handlingStrategy":"try-catch","validationCode":"if (typeof session.interrupt !== 'function') prepareAbortSignalFallback();","typeGuard":"const canInterrupt = (s: HarnessSession): s is HarnessSession & { interrupt: NonNullable<HarnessSession['interrupt']> } => typeof s.interrupt === 'function';","tryCatchPattern":"try { backend.interrupt({ turnId, reason }); } catch (e) { if (e.message === 'interruption is unavailable') { abortController.abort(); } else throw e; }","preventionTips":["Use AbortSignal-based cancel as the universal stop path","Hide turn-level stop controls for drivers without interrupt","Keep drivers updated to protocol versions with interrupt"],"tags":["interrupt","capability-missing","cancellation"],"backgroundTag":"unsupported-operation","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}