{"record":{"id":"657cb20f26b4d2cb","repo":"can1357/oh-my-pi","slug":"handoff-cancelled","errorCode":null,"errorMessage":"Handoff cancelled","messagePattern":"Handoff cancelled","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"info","filePath":"packages/coding-agent/src/session/session-handoff.ts","lineNumber":30,"sourceCode":"import type { Message, Model, ServiceTier, SimpleStreamOptions } from \"@oh-my-pi/pi-ai\";\nimport { logger, Snowflake } from \"@oh-my-pi/pi-utils\";\nimport type { ModelRegistry } from \"../config/model-registry\";\nimport type { Settings } from \"../config/settings\";\nimport { 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[];","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/session/session-handoff.ts#L12-L48","documentation":"throwIfHandoffAborted translates an aborted AbortSignal into a typed error for the handoff flow. When the signal was aborted with a plain DOMException AbortError (no richer reason), it throws Error(\"Handoff cancelled\") so callers can distinguish a user/environment cancellation from other abort causes.","triggerScenarios":"generateDocument calling throwIfHandoffAborted(handoffSignal) after the signal was aborted via controller.abort() with no custom reason (default AbortError).","commonSituations":"User cancelled the handoff prompt; session teardown or timeout aborted the controller mid-generation; upstream compaction logic aborted the handoff attempt.","solutions":["Treat this as an expected cancellation: catch and return quietly instead of retrying","If the handoff should proceed, restart it with a fresh, non-aborted AbortController","Find what aborted the signal (user action, timeout, teardown) and remove or delay that abort","Surface a 'cancelled' status to the user rather than an error report"],"exampleFix":"// before\nawait handoff.generateDocument(...); // throws 'Handoff cancelled'\n// after\ntry {\n  await handoff.generateDocument(...);\n} catch (err) {\n  if (err.message === \"Handoff cancelled\") return; // expected cancel\n  throw err;\n}","handlingStrategy":"try-catch","validationCode":"if (handoffSignal.aborted) return; // already cancelled; skip the call","typeGuard":null,"tryCatchPattern":"try {\n  await handoff.generateDocument(handoffSignal);\n} catch (err) {\n  if (err instanceof Error && err.message === \"Handoff cancelled\") return; // expected\n  throw err;\n}","preventionTips":["Check signal.aborted before starting handoff work","Distinguish cancellation from failure in your error handling","Abort with descriptive reasons when you own the controller","Avoid aborting handoff signals during routine UI interactions"],"tags":["abort","cancellation","handoff","compaction"],"backgroundTag":"operation-aborted","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}