paperclipai/paperclip · error

native_session_multi_run_unavailable

native_session_multi_run_unavailable

Error message

native_session_multi_run_unavailable

What it means

Thrown as a bare Error (code `native_session_multi_run_unavailable`) when a native session is being resumed via `options.existingSession` but that session object lacks an `attachRun` function. The runtime requires an attachRun capability to re-bind a retained provider session to a new run; without it, multi-run attachment of that session is unsupported and resume cannot proceed.

Solutions

  1. Recreate the session instead of resuming: drop existingSession and start a fresh native session run
  2. Ensure the code path producing the persisted session supplies attachRun (upgrade the adapter/runtime that created it)
  3. Verify the provider actually supports multi-run attachment before attempting to attach a retained sessionId
  4. Check for version mismatch between where the session was persisted and the current runner version

Example fix

// before
await startNativeSession({ existingSession: persistedSession }); // attachRun undefined
// after
if (typeof persistedSession.attachRun !== "function") {
  await startNativeSession({}); // fresh session
} else {
  await startNativeSession({ existingSession: persistedSession });
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (options.existingSession && typeof options.existingSession.attachRun !== "function") {
  throw new Error("Retained session lacks attachRun; start a fresh session instead");
}

Type guard

function supportsMultiRunAttach(s) {
  return !!s && typeof s.attachRun === "function";
}

Try / catch

try {
  await runtime.start({ existingSession: session });
} catch (e) {
  if (e.message === "native_session_multi_run_unavailable") {
    await runtime.start({}); // fall back to a fresh session
  } else throw e;
}

Prevention

When it happens

Trigger: Calling the native session runtime with `options.existingSession` set where `existingSession.attachRun === undefined` — i.e. a persisted/retained session produced by an older code path or provider adapter that never exposed attachRun.

Common situations: Resuming sessions created before the attachRun capability was introduced (version skew between persisted state and current runtime); using a provider adapter that does not support multi-run session attachment; a hand-constructed or partially hydrated PersistedNativeSession missing the attach callback.

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@3f1d897a7c (2026-09-18). Data as JSON: /api/errors/aff82c6f765856e3. Report an issue: GitHub.

Appendix: source

Thrown at packages/paperclip-runner/src/native-session-runtime.ts:1872

  const identity = {
    runId: input.binding.runId,
    sessionId: normalizedSessionId,
    companyId: input.binding.companyId,
    issueId: input.binding.issueId,
    agentId: input.binding.agentId,
  };
  let recovered = false;
  let session: NativeSession | null = null;
  let continuityBreak: {
    reason: string;
    previousDriverSessionId: string;
    previousProviderSessionId: string | null;
  } | null = null;
  let reconciledRecoveryCheckpoint: PersistedNativeSession | null = null;
  await options.onSessionAdmission?.();
  if (options.existingSession) {
    if (options.existingSession.attachRun === undefined) {
      throw new Error("native_session_multi_run_unavailable");
    }
    // Attaching can fail even after the retained session's identity passes the
    // static binding check (for example, when the provider lost multi-run
    // state). Prove the provider attachment before opening durable
    // control-plane state because ControlPlanePort has no rollback operation.
    try {
      await options.existingSession.attachRun({ identity });
    } catch (error) {
      // attachRun has no transactional guarantee: a provider may bind the new
      // run before reporting a later failure. Conservatively quarantine the
      // session so neither the old nor partially attached run can reuse it.
      await quarantineRetainedSession(
        options.existingSession,
        options.onSession,
        "native session attachment failed",
        cleanupDomain,
      );
      throw error;

View on GitHub (pinned to 3f1d897a7c)