{"record":{"id":"b7e6107ef2462d16","repo":"can1357/oh-my-pi","slug":"handoff-aborted-by-session","errorCode":null,"errorMessage":"Handoff aborted by session","messagePattern":"Handoff aborted by session","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"info","filePath":"packages/coding-agent/src/session/session-handoff.ts","lineNumber":34,"sourceCode":"import { obfuscateProviderContext } from \"../secrets/message-transform\";\nimport type { SecretObfuscator } from \"../secrets/obfuscator\";\nimport type { HandoffResult, SessionHandoffOptions } from \"./agent-session-types\";\nimport type { SessionManager } from \"./session-manager\";\n\nfunction createHandoffFileName(date = new Date()): string {\n\tconst fileTimestamp = date.toISOString().replace(/[:.]/g, \"-\");\n\treturn `handoff-${fileTimestamp}.md`;\n}\n\nfunction throwIfHandoffAborted(signal: AbortSignal): void {\n\tif (!signal.aborted) return;\n\tconst reason = signal.reason;\n\tif (reason instanceof DOMException && reason.name === \"AbortError\") {\n\t\tthrow new Error(\"Handoff cancelled\");\n\t}\n\tif (reason instanceof Error) throw reason;\n\tif (typeof reason === \"string\" && reason.length > 0) throw new Error(reason);\n\tthrow new Error(\"Handoff aborted by session\");\n}\n\n/** Capabilities borrowed from the owning AgentSession. */\nexport interface SessionHandoffHost {\n\tagent: Agent;\n\tsessionManager: SessionManager;\n\tsettings: Settings;\n\tmodelRegistry: ModelRegistry;\n\tsideStreamFn: StreamFn;\n\tobfuscator: SecretObfuscator | undefined;\n\tmodel(): Model | undefined;\n\tthinkingLevel(): ThinkingLevel | undefined;\n\tsessionId(): string;\n\tbaseSystemPrompt(): string[];\n\tsetSkipPostTurnMaintenance(timestamp: number | undefined): void;\n\tobfuscateTextForProvider(text: string | undefined): string | undefined;\n\tdeobfuscateFromProvider(text: string): string;\n\tconvertMessagesToLlm(messages: AgentMessage[], signal?: AbortSignal): Promise<Message[]>;","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/session/session-handoff.ts#L16-L52","documentation":"throwIfHandoffAborted is the catch-all abort translation: when the signal's reason is neither a plain AbortError, nor an Error, nor a non-empty string, it throws Error(\"Handoff aborted by session\"). This indicates the owning AgentSession aborted the handoff in a way that carried no descriptive reason.","triggerScenarios":"generateDocument's throwIfHandoffAborted check runs after signal.abort() was called with a reason that is not an Error/DOMException/string (e.g. abort(true) with a non-string truthy value, or undefined).","commonSituations":"Session shutdown/teardown aborting in-flight handoff generation; custom abort reasons of unexpected type; library code aborting controllers without a reason.","solutions":["Treat as a session-level cancellation: stop handoff work and clean up","Abort with a descriptive Error or string reason at the abort site so callers get a meaningful message","Catch this error and retry the handoff with a new AbortController if the session is active again","Audit the code paths that own the controller to see why the session aborted"],"exampleFix":"// before\ncontroller.abort(true); // opaque -> 'Handoff aborted by session'\n// after\ncontroller.abort(new Error(\"Session shutting down\")); // descriptive reason","handlingStrategy":"try-catch","validationCode":"if (handoffSignal.aborted) {\n  console.warn(\"Handoff aborted before start:\", handoffSignal.reason);\n  return;\n}","typeGuard":null,"tryCatchPattern":"try {\n  await handoff.generateDocument(handoffSignal);\n} catch (err) {\n  if (err instanceof Error && err.message === \"Handoff aborted by session\") {\n    // session-level teardown: stop work, no retry\n    return;\n  }\n  throw err;\n}","preventionTips":["Abort controllers with Error or string reasons so failures are diagnosable","Treat any aborted-signal error as terminal for that handoff attempt","Coordinate handoff lifetime with session teardown order","Retry only with a fresh controller after the session is active again"],"tags":["abort","cancellation","handoff","session"],"backgroundTag":"operation-aborted","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}