{"record":{"id":"c654e6f9d6526a25","repo":"pbakaus/impeccable","slug":"manual-edit-buffer-unreadable-err-message","errorCode":null,"errorMessage":"manual_edit_buffer_unreadable: {err.message}","messagePattern":"manual_edit_buffer_unreadable: (.+?)","errorType":"exception","errorClass":null,"httpStatus":500,"severity":"error","filePath":"skill/scripts/live/manual-edits-buffer.mjs","lineNumber":44,"sourceCode":"}\n\nexport function readBufferStrict(cwd = process.cwd()) {\n  return readBufferInternal(cwd, { strict: true });\n}\n\nfunction readBufferInternal(cwd, { strict }) {\n  const filePath = getBufferPath(cwd);\n  try {\n    const raw = fs.readFileSync(filePath, 'utf-8');\n    const parsed = JSON.parse(raw);\n    if (!parsed || typeof parsed !== 'object' || !Array.isArray(parsed.entries)) {\n      if (strict) throw new Error('manual_edit_buffer_invalid_schema');\n      return { version: BUFFER_VERSION, entries: [] };\n    }\n    return { version: BUFFER_VERSION, entries: parsed.entries };\n  } catch (err) {\n    if (strict && err?.code !== 'ENOENT') {\n      throw new Error('manual_edit_buffer_unreadable: ' + (err.message || String(err)));\n    }\n    return { version: BUFFER_VERSION, entries: [] };\n  }\n}\n\nexport function writeBuffer(cwd, buffer) {\n  const filePath = getBufferPath(cwd);\n  fs.mkdirSync(path.dirname(filePath), { recursive: true });\n  fs.writeFileSync(filePath, JSON.stringify({ version: BUFFER_VERSION, entries: buffer.entries }, null, 2));\n}\n\n/**\n * Merge a new entry into the buffer. For each op in the new entry, if there's\n * already a buffered op for the same (pageUrl, ref), update that op's newText\n * and keep its original originalText (the true source state). Otherwise add\n * the op (creating an entry if needed).\n *\n * Multiple ops in one Save are allowed; each is keyed by (pageUrl, ref).","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/pbakaus/impeccable/blob/f88b2837a7d7c3182e46307bbbb091a1ed547571/skill/scripts/live/manual-edits-buffer.mjs#L26-L62","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Read the appended underlying message — 'Unexpected token' pinpoints the JSON syntax break; EACCES pinpoints permissions","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","Fix ownership/permissions on .impeccable/live/ if the code is EACCES","Re-stage the discarded edits through the browser Save flow after resetting"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import fs from 'node:fs';\n\nconst p = '.impeccable/live/pending-manual-edits.json';\nif (fs.existsSync(p)) {\n  try {\n    JSON.parse(fs.readFileSync(p, 'utf-8'));\n  } catch (parseErr) {\n    throw new Error(`buffer is corrupt — repair or archive ${p}: ${parseErr.message}`);\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  buffer = readBufferStrict(cwd);\n} catch (err) {\n  if (err?.message?.startsWith('manual_edit_buffer_unreadable:')) {\n    // err.message carries the JSON/IO cause. ENOENT never reaches here.\n    archiveCorruptBuffer(); // mv pending-manual-edits.json pending-manual-edits.json.corrupt\n    buffer = { version: 1, entries: [] };\n  } else {\n    throw err;\n  }\n}","preventionTips":["Avoid killing the live server mid-Save: a truncated buffer write is the usual corruption source","Read the appended underlying message first — 'Unexpected token' means fix JSON, EACCES means fix permissions","Archive corrupt buffers instead of deleting, so the staged edits can be recovered manually"],"tags":["json","io","buffer","manual-edits"],"backgroundTag":"malformed-json-file","analyzedSha":"f88b2837a7d7c3182e46307bbbb091a1ed547571","analyzedAt":"2026-08-18T04:58:36.608Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}