paperclipai/paperclip · error

interruption is unavailable

Error message

interruption is unavailable

What it means

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.

Source

Thrown at packages/paperclip-runner/src/backends/harness-driver-backend.ts:688

      this.#rethrowProtocolIntegrity(error);
      throw error;
    }
  }

  steer(input: {
    turnId: string;
    message: { role: "user"; text: string };
    correlationId?: string;
  }) {
    this.#assertProtocolIntegrity();
    if (this.#session.steer === undefined)
      throw new Error("steering is unavailable");
    return this.#withProtocolIntegrity(() => this.#session.steer!(input));
  }

  interrupt(input: { turnId?: string; reason?: string }) {
    if (this.#session.interrupt === undefined)
      throw new Error("interruption is unavailable");
    return this.#session.interrupt(input);
  }

  cancel(input: { reason: string; signal: AbortSignal }) {
    if (input.signal.aborted) {
      throw (
        input.signal.reason ?? new Error("native session cancellation aborted")
      );
    }
    // This flag is the adapter's synchronous publication boundary. Provider
    // interruption happens afterward as passive cleanup, so a slow or broken
    // transport cannot synthesize or publish new accepted output for the turn.
    this.#explicitlyCancelled = true;
    const interrupt = this.#session.interrupt;
    return {
      cleanup:
        interrupt === undefined
          ? Promise.resolve()

View on GitHub (pinned to 01ad858492)

Solutions

  1. Use the backend's cancel() path (AbortSignal-based) instead of turn-level interrupt when interrupt is unsupported
  2. Upgrade the driver/adapter to one implementing interrupt
  3. Disable or hide turn-level stop controls for agents that report no interrupt capability
  4. Feature-detect interrupt support before offering it

Example fix

// before
backend.interrupt({ turnId, reason: 'user-cancel' });
// after
if (!backend.canInterrupt()) {
  abortController.abort(); // drives cancel(signal) path
} else {
  backend.interrupt({ turnId, reason: 'user-cancel' });
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (typeof session.interrupt !== 'function') prepareAbortSignalFallback();

Type guard

const canInterrupt = (s: HarnessSession): s is HarnessSession & { interrupt: NonNullable<HarnessSession['interrupt']> } => typeof s.interrupt === 'function';

Try / catch

try { backend.interrupt({ turnId, reason }); } catch (e) { if (e.message === 'interruption is unavailable') { abortController.abort(); } else throw e; }

Prevention

When it happens

Trigger: 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().

Common situations: 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.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/2e0b4c09b588c948. Report an issue: GitHub.