pbakaus/impeccable · error

manual_edit_buffer_unreadable: {err.message}

Error message

manual_edit_buffer_unreadable: {err.message}

What it means

readBufferStrict() failed before any schema check: fs.readFileSync or JSON.parse threw with an error whose code is not ENOENT (a missing file legitimately falls back to an empty buffer). The thrown message is 'manual_edit_buffer_unreadable: ' plus the underlying error text — most often a JSON syntax error ('Unexpected token ... in ...pending-manual-edits.json') from a corrupt or truncated file, or EACCES/EISDIR from filesystem problems.

Source

Thrown at skill/scripts/live/manual-edits-buffer.mjs:44

}

export function readBufferStrict(cwd = process.cwd()) {
  return readBufferInternal(cwd, { strict: true });
}

function readBufferInternal(cwd, { strict }) {
  const filePath = getBufferPath(cwd);
  try {
    const raw = fs.readFileSync(filePath, 'utf-8');
    const parsed = JSON.parse(raw);
    if (!parsed || typeof parsed !== 'object' || !Array.isArray(parsed.entries)) {
      if (strict) throw new Error('manual_edit_buffer_invalid_schema');
      return { version: BUFFER_VERSION, entries: [] };
    }
    return { version: BUFFER_VERSION, entries: parsed.entries };
  } catch (err) {
    if (strict && err?.code !== 'ENOENT') {
      throw new Error('manual_edit_buffer_unreadable: ' + (err.message || String(err)));
    }
    return { version: BUFFER_VERSION, entries: [] };
  }
}

export function writeBuffer(cwd, buffer) {
  const filePath = getBufferPath(cwd);
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
  fs.writeFileSync(filePath, JSON.stringify({ version: BUFFER_VERSION, entries: buffer.entries }, null, 2));
}

/**
 * Merge a new entry into the buffer. For each op in the new entry, if there's
 * already a buffered op for the same (pageUrl, ref), update that op's newText
 * and keep its original originalText (the true source state). Otherwise add
 * the op (creating an entry if needed).
 *
 * Multiple ops in one Save are allowed; each is keyed by (pageUrl, ref).

View on GitHub (pinned to f88b2837a7)

Solutions

  1. Read the appended underlying message — 'Unexpected token' pinpoints the JSON syntax break; EACCES pinpoints permissions
  2. Repair the JSON syntax, or archive the file away (e.g. mv pending-manual-edits.json pending-manual-edits.json.bak) to reset the buffer, accepting that staged edits are lost
  3. Fix ownership/permissions on .impeccable/live/ if the code is EACCES
  4. Re-stage the discarded edits through the browser Save flow after resetting
Defensive patterns

Strategy: validation

Validate before calling

import fs from 'node:fs';

const p = '.impeccable/live/pending-manual-edits.json';
if (fs.existsSync(p)) {
  try {
    JSON.parse(fs.readFileSync(p, 'utf-8'));
  } catch (parseErr) {
    throw new Error(`buffer is corrupt — repair or archive ${p}: ${parseErr.message}`);
  }
}

Try / catch

try {
  buffer = readBufferStrict(cwd);
} catch (err) {
  if (err?.message?.startsWith('manual_edit_buffer_unreadable:')) {
    // err.message carries the JSON/IO cause. ENOENT never reaches here.
    archiveCorruptBuffer(); // mv pending-manual-edits.json pending-manual-edits.json.corrupt
    buffer = { version: 1, entries: [] };
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: pending-manual-edits.json is truncated mid-write (crash during writeBuffer), contains a merge-conflict artifact or stray characters making it invalid JSON, has wrong permissions (EACCES), or a directory sits at the file's path.

Common situations: Server/process killed while writing the buffer; concurrent writers interleaving; hand edits introducing syntax errors; restrictive permissions on .impeccable/live/ after a repo move or restore.

Related errors


AI-assisted analysis of pbakaus/impeccable@f88b2837a7 (2026-08-18). Data as JSON: /api/errors/c654e6f9d6526a25. Report an issue: GitHub.