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

  1. Do nothing — the session is already compacted; continue the conversation and compact later.
  2. Guard retries: don't re-call compaction after a successful result (track `compactionCommitted`/result state).
  3. 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

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


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/d02e1ff2a2455a92. Report an issue: GitHub.