can1357/oh-my-pi · info
Already compacted
Error message
Already compacted
What it means
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.
Source
Thrown at packages/coding-agent/src/session/session-maintenance.ts:817
candidate.provider === activeModel.provider &&
shouldUseProviderNativeCompaction(candidate, effectiveSettings)
: undefined,
);
if (requireProviderRemote && compactionCandidates.length === 0) {
this.#host.emitNotice(
"warning",
`remote compaction is unavailable for ${activeModel.id}; trying the next preferred method`,
"compaction",
);
return await this.compact(customInstructions, options, selectedMethodIndex + 1, compactionAbortController);
}
const pathEntries = this.#host.sessionManager.getBranch();
const preparation = prepareCompaction(pathEntries, effectiveSettings, activeModel, this.#tokenizer);
if (!preparation) {
// Check why we can't compact
const lastEntry = pathEntries[pathEntries.length - 1];
if (lastEntry?.type === "compaction") {
throw new Error("Already compacted");
}
throw new Error("Nothing to compact (session too small)");
}
let hookCompaction: CompactionResult | undefined;
let fromExtension = false;
let preserveData: Record<string, unknown> | undefined;
if (this.#host.extensionRunner?.hasHandlers("session_before_compact")) {
const result = (await this.#host.extensionRunner.emit({
type: "session_before_compact",
preparation,
branchEntries: pathEntries,
customInstructions,
signal: compactionAbortController.signal,
})) as SessionBeforeCompactResult | undefined;
if (result?.cancel) {View on GitHub (pinned to 9690622007)
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.
Example fix
// before for (let i = 0; i < 2; i++) await session.compact(); // after const result = await session.compact(); if (result?.committed) return; // do not compact again immediately
Defensive patterns
Strategy: try-catch
Validate before calling
// Inspect the branch tip via the session manager before compacting const branch = sessionManager.getBranch(); const alreadyCompacted = branch[branch.length - 1]?.type === "compaction";
Type guard
function isCompactionEntry(e?: { type: string }): boolean {
return e?.type === "compaction";
} Try / catch
try {
await session.compact();
} catch (err) {
if (err instanceof Error && err.message === "Already compacted") return; // benign
throw err;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- goal is already complete
- Security scan ${options.scanId} has already been published
- No model selected for handoff
- Compaction already in progress
- No model selected
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/d02e1ff2a2455a92.
Report an issue: GitHub.