can1357/oh-my-pi · critical · AggregateError

Session append failed and its partial bytes could not be rol

Error message

Session append failed and its partial bytes could not be rolled back

What it means

When appendSync's write fails, SessionStorage tries ftruncateSync to roll the session file back to its original size so no partial JSONL bytes corrupt it. If the write AND the rollback both fail, it throws an AggregateError containing both errors with this message, because the session file is now left in a partially-written state that cannot be safely repaired automatically.

Source

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

	}

	#writeNow(line: string): void {
		const originalSize = fs.fstatSync(this.#fd).size;
		const buf = Buffer.from(line, "utf-8");
		let offset = 0;
		try {
			while (offset < buf.length) {
				const written = fs.writeSync(this.#fd, buf, offset, buf.length - offset);
				if (written === 0) {
					throw new Error("Short write");
				}
				offset += written;
			}
		} catch (writeError) {
			try {
				fs.ftruncateSync(this.#fd, originalSize);
			} catch (rollbackError) {
				throw new AggregateError(
					[toError(writeError), toError(rollbackError)],
					"Session append failed and its partial bytes could not be rolled back",
				);
			}
			throw writeError;
		}
	}

	appendSync(line: string): void {
		if (this.#closed) throw new Error("Writer closed");
		if (this.#error) throw this.#error;
		// Write in-body so software crash after the call still sees the entry.
		// Microtask batching used to leave completed transcript lines only in
		// memory until the next event-loop turn; process crash then lost every
		// post-checkpoint event. flush/flushSync remain no-op drains (no fsync).
		try {
			this.#writeNow(line);
		} catch (err) {

View on GitHub (pinned to 9690622007)

Solutions

  1. Free disk space or restore write access to the volume immediately — the session file may contain a partial line.
  2. Manually inspect the session .jsonl file and delete the trailing incomplete line to restore a valid JSONL stream.
  3. If the volume went read-only, remount it read-write (or move the session directory to a healthy disk) before continuing.
  4. Copy/backup the session file before any manual repair, then let the app recreate entries from the last valid line.

Example fix

// manual repair of the corrupted tail
node -e "
  const fs = require('fs');
  const p = process.argv[1];
  const lines = fs.readFileSync(p, 'utf8').split('\n');
  while (lines.length && (!lines[lines.length-1] || !safeJson(lines[lines.length-1]))) lines.pop();
  fs.writeFileSync(p, lines.join('\n') + '\n');
" session-file.jsonl
Defensive patterns

Strategy: try-catch

Validate before calling

const s = await statfs(sessionDir);
if (s.bavail * s.bsize < 10 * 1024 * 1024) {
  // refuse to run sessions on a nearly-full disk
  throw new Error("Insufficient disk space for session storage");
}

Type guard

function isAggregateWriteFailure(err: unknown): err is AggregateError {
  return err instanceof AggregateError &&
    err.message.includes("partial bytes could not be rolled back");
}

Try / catch

try {
  storage.appendSync(line);
} catch (err) {
  if (isAggregateWriteFailure(err)) {
    for (const e of err.errors) logger.error("Session append + rollback failed", { e });
    // session file may hold a partial line — quarantine/validate it before further use
  } else throw err;
}

Prevention

When it happens

Trigger: writeSync fails (e.g. ENOSPC, EIO) and the subsequent ftruncateSync also fails — typically because the disk is still full (truncate needs a metadata write), the fd is broken, or the filesystem went read-only.

Common situations: Fully saturated disk on a long-running agent session where the original write fails on space and truncation also fails on the same condition; device errors or a volume remounted read-only mid-session.

Related errors


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