{"record":{"id":"d02e1ff2a2455a92","repo":"can1357/oh-my-pi","slug":"already-compacted","errorCode":null,"errorMessage":"Already compacted","messagePattern":"Already compacted","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"packages/coding-agent/src/session/session-maintenance.ts","lineNumber":817,"sourceCode":"\t\t\t\t\t\t\tcandidate.provider === activeModel.provider &&\n\t\t\t\t\t\t\tshouldUseProviderNativeCompaction(candidate, effectiveSettings)\n\t\t\t\t\t: undefined,\n\t\t\t);\n\t\t\tif (requireProviderRemote && compactionCandidates.length === 0) {\n\t\t\t\tthis.#host.emitNotice(\n\t\t\t\t\t\"warning\",\n\t\t\t\t\t`remote compaction is unavailable for ${activeModel.id}; trying the next preferred method`,\n\t\t\t\t\t\"compaction\",\n\t\t\t\t);\n\t\t\t\treturn await this.compact(customInstructions, options, selectedMethodIndex + 1, compactionAbortController);\n\t\t\t}\n\t\t\tconst pathEntries = this.#host.sessionManager.getBranch();\n\t\t\tconst preparation = prepareCompaction(pathEntries, effectiveSettings, activeModel, this.#tokenizer);\n\t\t\tif (!preparation) {\n\t\t\t\t// Check why we can't compact\n\t\t\t\tconst lastEntry = pathEntries[pathEntries.length - 1];\n\t\t\t\tif (lastEntry?.type === \"compaction\") {\n\t\t\t\t\tthrow new Error(\"Already compacted\");\n\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) {","sourceCodeStart":799,"sourceCodeEnd":835,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/session/session-maintenance.ts#L799-L835","documentation":"Thrown when `prepareCompaction` returns null and the last branch entry is already a compaction entry — the session has already been compacted at its tip and there is nothing new to compact again. It distinguishes the 'already compacted' case from the 'session too small' case.","triggerScenarios":"Running manual compaction twice in a row without any new conversation entries after the first successful compaction; programmatically calling compact() in a loop or retry after a compaction already committed.","commonSituations":"A retry wrapper re-invoking compact after success; a script that compacts every N turns firing twice for one turn; user pressing /compact again immediately after it completed.","solutions":["Do nothing — the session is already compacted; continue the conversation and compact later.","Guard retries: don't re-call compaction after a successful result (track `compactionCommitted`/result state).","If you truly need a fresh summary, send new messages first or start/branch a new session."],"exampleFix":"// before\nfor (let i = 0; i < 2; i++) await session.compact();\n// after\nconst result = await session.compact();\nif (result?.committed) return; // do not compact again immediately","handlingStrategy":"try-catch","validationCode":"// Inspect the branch tip via the session manager before compacting\nconst branch = sessionManager.getBranch();\nconst alreadyCompacted = branch[branch.length - 1]?.type === \"compaction\";","typeGuard":"function isCompactionEntry(e?: { type: string }): boolean {\n  return e?.type === \"compaction\";\n}","tryCatchPattern":"try {\n  await session.compact();\n} catch (err) {\n  if (err instanceof Error && err.message === \"Already compacted\") return; // benign\n  throw err;\n}","preventionTips":["Track compaction results; never retry compact() after a committed success.","Debounce compaction triggers so one turn can't fire it twice.","Treat this error as a no-op signal, not a failure, in automation."],"tags":["compaction","idempotency","state"],"backgroundTag":"already-compacted","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}