can1357/oh-my-pi · error · Error

Entry ${branchFromId} not found

Error message

Entry ${branchFromId} not found

What it means

branch() moves the session leaf to an earlier entry so subsequent appends form a new branch of the entry tree. It throws if branchFromId does not exist in the session index, since there is no entry to move the leaf to. Existing entries are never modified or deleted; the id must point at a live entry in the currently loaded session.

Source

Thrown at packages/coding-agent/src/session/session-manager.ts:2613

	/** All session entries (excludes header). Returns a shallow copy. */
	getEntries(): SessionEntry[] {
		return [...this.#entries];
	}

	/**
	 * The session as a tree. A well-formed session has exactly one root; orphaned
	 * entries (broken parent chain) are returned as roots too.
	 */
	getTree(): SessionTreeNode[] {
		return this.#index.tree(this.#entries);
	}

	/**
	 * Move the leaf to an earlier entry so the next append forms a new branch.
	 * Existing entries are never modified or deleted.
	 */
	branch(branchFromId: string): void {
		if (!this.#index.has(branchFromId)) throw new Error(`Entry ${branchFromId} not found`);
		this.#setLeaf(branchFromId);
	}

	/** Reset the leaf to null so the next append creates a new root entry. */
	resetLeaf(): void {
		this.#setLeaf(null);
	}

	/**
	 * Durably move the active branch past a discarded entry.
	 *
	 * The loader reconstructs the active branch from the last physical journal
	 * entry, so changing the in-memory leaf alone is lost on reload. Known
	 * metadata children are chained onto the discarded entry's parent before the
	 * entry is removed. If any child may carry content, the subtree is preserved
	 * off-branch instead. Both paths append a metadata-only branch marker and
	 * rewrite the journal, making the selected path durable.
	 */

View on GitHub (pinned to 9690622007)

Solutions

  1. Fetch valid entry ids from the current SessionManager (entry list / traversal) instead of cached ids.
  2. Use resetLeaf() if you actually want to branch from a fresh root rather than an existing entry.
  3. Verify the target entry exists in the index before calling branch.
  4. Load the session containing the target entry before branching.

Example fix

// before
mgr.branch(cachedId); // Entry <id> not found
// after
const entries = mgr.getEntries();
const target = entries.find(e => e.id === cachedId);
if (target) mgr.branch(target.id); else mgr.resetLeaf();
Defensive patterns

Strategy: validation

Validate before calling

if (!mgr.hasEntry(branchFromId)) {
  mgr.resetLeaf(); // branch from a fresh root instead
  return;
}

Type guard

function canBranch(mgr, id) {
  return mgr.getEntry(id) != null;
}

Try / catch

try {
  mgr.branch(id);
} catch (err) {
  if (/Entry .* not found/.test(err.message)) {
    mgr.resetLeaf(); // fall back to a new root branch
  } else throw err;
}

Prevention

When it happens

Trigger: Calling SessionManager.branch(branchFromId) with an id not in the current session — id from a different session/file, an entry removed by compaction, or a stale id after the session was reloaded or reset.

Common situations: Building a 'fork from earlier message' UI that cached entry ids across a session reload; forking from another session's transcript; branching from an id destroyed by compaction.

Related errors


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