can1357/oh-my-pi · error · Error

could not relocate the session back to ${snapshot.sessionDir

Error message

could not relocate the session back to ${snapshot.sessionDir} (${error instanceof Error ? error.message : String(error)}); the session file remains at ${movedFile}

What it means

rollbackMove() attempts to relocate a session back to its original directory captured in a state snapshot. If that move fails, the original moveTo error is wrapped in this message that reports both the intended destination and where the session file currently sits, so the caller knows the session was NOT restored and data is at movedFile. The wrapper prevents losing the underlying cause while leaving state unrestored.

Source

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

	/**
	 * Undo a {@link moveTo} using a {@link captureState} snapshot: rename the
	 * session and artifacts back into the captured bucket, then restore the
	 * captured metadata (cwd, header, additionalDirectories). The captured
	 * header is persisted after relocation so a fresh open of the source
	 * session sees the pre-move metadata, including workspace roots the move
	 * filtered out. Rollbacks must not re-enter forward-move hooks, so this
	 * bypasses AgentSession entirely. If the rename-back itself fails, the
	 * manager stays pointed at the actual moved file (restoring the snapshot
	 * would split the transcript across a recreated source and the stranded
	 * target) and the error names where the session file actually lives.
	 */
	async rollbackMove(snapshot: SessionManagerStateSnapshot): Promise<void> {
		try {
			const targetSessionDir = snapshot.sessionFile ? path.dirname(snapshot.sessionFile) : snapshot.sessionDir;
			await this.moveTo(snapshot.cwd, targetSessionDir);
		} catch (error) {
			const movedFile = this.getSessionFile();
			throw new Error(
				`could not relocate the session back to ${snapshot.sessionDir} (${error instanceof Error ? error.message : String(error)}); the session file remains at ${movedFile}`,
			);
		}
		this.restoreState(snapshot);
		// The inverse moveTo already rewrote the source file with the
		// target-filtered header. Persist the captured one so disk and memory
		// agree after a fresh open.
		if (this.#persist && this.#sessionFile) {
			this.#forceFileCreation = true;
			this.#rewriteRequired = true;
			await this.#rewriteAtomically();
		}
	}
	/** Switch to a different session file (resume / branch). */
	async setSessionFile(sessionFile: string): Promise<void> {
		await this.#setSessionFile(sessionFile);
	}

View on GitHub (pinned to 9690622007)

Solutions

  1. Recreate the original session directory (snapshot.sessionDir) with write permissions, then call rollbackMove again.
  2. Manually move the file from getSessionFile()/movedFile back to the target directory.
  3. If the original directory is intentionally gone, adopt the current location instead of rolling back.
  4. Read the inner parenthesized error for the precise filesystem cause (ENOENT, EACCES, EBUSY).

Example fix

// before
await mgr.rollbackMove(snapshot); // ENOENT if dir deleted
// after
if (!existsSync(snapshot.sessionDir)) {
  mkdirSync(snapshot.sessionDir, { recursive: true });
}
await mgr.rollbackMove(snapshot);
Defensive patterns

Strategy: try-catch

Validate before calling

if (!existsSync(snapshot.sessionDir)) {
  mkdirSync(snapshot.sessionDir, { recursive: true });
}

Type guard

null

Try / catch

try {
  await mgr.rollbackMove(snapshot);
} catch (err) {
  // session file is still at the path in err.message; move it manually
  logger.error("Rollback failed; session left in place", { err });
}

Prevention

When it happens

Trigger: Calling SessionManager.rollbackMove(snapshot) when moveTo(snapshot.cwd, targetSessionDir) throws — e.g. the original directory no longer exists, permissions changed, the target path is not writable, or snapshot.sessionFile points into a removed directory.

Common situations: Undoing a session move after the original project directory was deleted or renamed; read-only filesystem; cross-device rename restrictions; concurrent process holding a lock on the destination.

Related errors


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