{"record":{"id":"5b878e3cbe18fd60","repo":"can1357/oh-my-pi","slug":"compaction-cancelled","errorCode":null,"errorMessage":"Compaction cancelled","messagePattern":"Compaction cancelled","errorType":"exception","errorClass":"CompactionCancelledError","httpStatus":null,"severity":"info","filePath":"packages/coding-agent/src/session/session-maintenance.ts","lineNumber":836,"sourceCode":"\t\t\t\t}\n\t\t\t\tthrow new Error(\"Nothing to compact (session too small)\");\n\t\t\t}\n\n\t\t\tlet hookCompaction: CompactionResult | undefined;\n\t\t\tlet fromExtension = false;\n\t\t\tlet preserveData: Record<string, unknown> | undefined;\n\n\t\t\tif (this.#host.extensionRunner?.hasHandlers(\"session_before_compact\")) {\n\t\t\t\tconst result = (await this.#host.extensionRunner.emit({\n\t\t\t\t\ttype: \"session_before_compact\",\n\t\t\t\t\tpreparation,\n\t\t\t\t\tbranchEntries: pathEntries,\n\t\t\t\t\tcustomInstructions,\n\t\t\t\t\tsignal: compactionAbortController.signal,\n\t\t\t\t})) as SessionBeforeCompactResult | undefined;\n\n\t\t\t\tif (result?.cancel) {\n\t\t\t\t\tthrow new CompactionCancelledError();\n\t\t\t\t}\n\n\t\t\t\tif (result?.compaction) {\n\t\t\t\t\thookCompaction = result.compaction;\n\t\t\t\t\tfromExtension = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst compactionPrep = await this.#prepareCompactionFromHooks(preparation, hookCompaction);\n\t\t\tif (compactionPrep.kind !== \"fromHook\") methodAttempted = true;\n\n\t\t\t// Focus instructions require an LLM summary, so the preference resolver\n\t\t\t// only selects snapcompact for an undirected manual compaction.\n\t\t\tconst wantsSnapcompact = compactionPrep.kind !== \"fromHook\" && selectedMethod === \"snapcompact\";\n\t\t\tconst snapcompactReady = wantsSnapcompact;\n\t\t\tconst snapcompactShapeSetting = this.#host.settings.get(\"snapcompact.shape\");\n\t\t\tlet snapcompactShape: snapcompact.Shape | undefined;\n\t\t\t// Claude refuses inputs that reproduce its own reasoning as text","sourceCodeStart":818,"sourceCodeEnd":854,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/session/session-maintenance.ts#L818-L854","documentation":"A `CompactionCancelledError` thrown when a `session.before_compact` extension hook returns `{ cancel: true }`, aborting the compaction before it runs. Extensions use this to veto compaction (e.g. to defer it or handle context pressure differently); the error propagates so callers know compaction did not happen by deliberate cancellation, not failure.","triggerScenarios":"Any installed extension implementing the `before_compact` hook returning `cancel: true` — commonly when the extension's own logic decides context is fine, or when it wants to run a custom compaction and cancel the built-in one.","commonSituations":"Context-management extensions (custom summarizers, memory tools) installed by the user; a hook crashing-but-catching into a cancel; recently installed extension the user forgot about, making /compact mysteriously abort.","solutions":["Identify the extension registering a before_compact hook and check why it cancels; disable it if unwanted.","Catch CompactionCancelledError separately and treat it as a benign, intentional abort.","If the extension should replace rather than cancel, let its `result.compaction` path supply a compaction result instead."],"exampleFix":"// before\ntry { await session.compact(); } catch (e) { report(e); }\n// after\ntry { await session.compact(); }\ncatch (e) {\n  if (e instanceof CompactionCancelledError) return; // extension vetoed\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"const handler = (e) => e.type === \"before_compact\" ? { cancel: false } : undefined; // audit installed extensions that register before_compact hooks","typeGuard":null,"tryCatchPattern":"import { CompactionCancelledError } from \"./compaction-errors\";\ntry {\n  await session.compact();\n} catch (err) {\n  if (err instanceof CompactionCancelledError) return; // intentional extension veto\n  throw err;\n}","preventionTips":["Audit installed extensions for before_compact hooks when compaction unexpectedly aborts.","Handle CompactionCancelledError as a distinct, benign outcome in callers.","Extensions should return a compaction result (result.compaction) instead of plain cancel when they replace the flow."],"tags":["compaction","extension-hook","cancelled"],"backgroundTag":"operation-cancelled-by-hook","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}