can1357/oh-my-pi · critical · Error

Failed to replace session file after EPERM (original: ${toEr

Error message

Failed to replace session file after EPERM (original: ${toError(renameError).message}; retry: ${toError(replaceError).message}; rollback: ${rollbackError.message})

What it means

writeTextAtomic replaces the session file via a temp-file rename. When the initial rename fails with EPERM (seen on some platforms when the target is held open, e.g. by antivirus/indexers or another process), the code retries and, on failure, attempts to roll back by renaming a backup over the target. If the rollback also fails, this Error is thrown combining all three messages, leaving the replacement incomplete — the original Error is attached as cause.

Source

Thrown at packages/coding-agent/src/session/session-storage.ts:401

				this.renameSync(backupPath, targetPath);
			} catch (restoreErr) {
				logger.warn("Failed to restore backup after commitGuard rejection", {
					sessionFile: targetPath,
					backupPath,
					error: toError(restoreErr).message,
				});
			}
			this.#discardTemp(tempPath, targetPath);
			return;
		}
		try {
			this.renameSync(tempPath, targetPath);
		} catch (replaceError) {
			try {
				this.renameSync(backupPath, targetPath);
			} catch (rollbackErr) {
				const rollbackError = toError(rollbackErr);
				throw new Error(
					`Failed to replace session file after EPERM (original: ${toError(renameError).message}; retry: ${
						toError(replaceError).message
					}; rollback: ${rollbackError.message})`,
					{ cause: toError(renameError) },
				);
			}
			throw toError(replaceError);
		}
		try {
			fs.unlinkSync(backupPath);
		} catch (err) {
			if (!isEnoent(err)) {
				logger.warn("Failed to remove session rewrite backup", {
					sessionFile: targetPath,
					backupPath,
					error: toError(err).message,
				});
			}

View on GitHub (pinned to 9690622007)

Solutions

  1. Close other processes holding the session file (second omp instance, editors, sync clients) and retry the operation.
  2. Exclude the session directory from antivirus/real-time scanning or pause file-sync software (OneDrive/Dropbox) for ~/.omp.
  3. Check directory permissions: ensure the user can create/rename/delete files in the session directory.
  4. Inspect the error's cause and message trio to determine which stage failed; restore from the .bak/backup file if present, or recreate the session from the last valid JSONL.

Example fix

// before: operation fails while Dropbox syncs the session dir
await storage.writeTextAtomic(path, text);
// after: pause sync client or relocate sessions
const dir = path.join(os.homedir(), ".omp", "sessions"); // ensure not inside a synced folder
await storage.writeTextAtomic(path, text);
Defensive patterns

Strategy: retry

Validate before calling

import { access, constants } from "node:fs/promises";
await access(sessionDir, constants.W_OK); // throws early if dir not writable
// also ensure no second omp instance holds the file:
// check for a lock/pid file in the session dir before writing

Type guard

function isAtomicReplaceFailure(err: unknown): err is Error & { cause: unknown } {
  return err instanceof Error &&
    err.message.startsWith("Failed to replace session file after EPERM");
}

Try / catch

try {
  await storage.writeTextAtomic(target, text);
} catch (err) {
  if (isAtomicReplaceFailure(err)) {
    logger.error("Atomic session replace failed (lock/AV/sync client?)", { cause: err.cause });
    // look for leftover backup file to restore, then retry after unlocking
  } else throw err;
}

Prevention

When it happens

Trigger: renameSync of the temp file fails (typically EPERM/EACCES because the target file is locked by another process, a sync client, or Windows AV), the retry rename also fails, and restoring the backup over the target fails too (e.g. backup already moved or target locked).

Common situations: Windows file locking by antivirus/Defender or Dropbox/OneDrive syncing the session directory; two omp processes running against the same session file; read-only or permission-restricted session directory after a permission change.

Related errors


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