pbakaus/impeccable · error
manual_edit_buffer_invalid_schema
Error message
manual_edit_buffer_invalid_schema
What it means
readBufferStrict() (skill/scripts/live/manual-edits-buffer.mjs) reads the pending-manual-edits buffer at .impeccable/live/pending-manual-edits.json. The file parsed as valid JSON, but the root is not an object or parsed.entries is not an array — i.e. the shape { version: 1, entries: [...] } is violated. Strict readers (the apply/commit path) throw manual_edit_buffer_invalid_schema; lenient readers (readBuffer) silently reset to an empty buffer instead.
Solutions
- Inspect .impeccable/live/pending-manual-edits.json
- Rewrite it as { "version": 1, "entries": [ ... ] }, preserving the staged entries if they are recoverable
- Otherwise archive/delete the file to start a clean buffer — staged browser edits recorded in it are discarded and must be re-made
Example fix
// .impeccable/live/pending-manual-edits.json — before
[ { "id": "e1", "text": "..." } ]
// after
{ "version": 1, "entries": [ { "id": "e1", "text": "..." } ] } Defensive patterns
Strategy: type-guard
Validate before calling
import fs from 'node:fs';
const p = '.impeccable/live/pending-manual-edits.json';
if (fs.existsSync(p)) {
const parsed = JSON.parse(fs.readFileSync(p, 'utf-8'));
if (!parsed || typeof parsed !== 'object' || !Array.isArray(parsed.entries)) {
throw new Error('buffer schema drifted — archive the file and re-stage edits');
}
} Type guard
const isValidEditBuffer = (v) => !!v && typeof v === 'object' && !Array.isArray(v) && Array.isArray(v.entries);
Try / catch
try {
buffer = readBufferStrict(cwd);
} catch (err) {
if (err?.message === 'manual_edit_buffer_invalid_schema') {
// Reset path: archive the drifted buffer, accept that staged edits are lost,
// re-stage via the browser Save flow.
fs.renameSync(bufferPath, bufferPath + '.invalid');
buffer = { version: 1, entries: [] };
} else {
throw err;
}
} Prevention
- Never hand-edit pending-manual-edits.json — stage edits through the browser Save path
- Treat buffer schema changes as migration points: transform old shapes on skill upgrade instead of keeping them
- Archive (rename) rather than delete drifted buffers so staged content stays inspectable
When it happens
Trigger: The buffer file was hand-edited or written in a different format: root is an array of entries, entries was renamed, or the whole staged-edit structure from an older/newer skill version is present.
Common situations: An agent editing the buffer directly instead of going through the browser Save path; skill upgrades that changed the buffer schema; hand-resolved merge conflicts on the file.
Related errors
- manual_edit_buffer_unreadable
- config.json must be an object
- AI copy-edit batch did not return a valid completion…
- comp-diff: cannot read spec
- comp-spec: cannot read regions
AI-assisted analysis of pbakaus/impeccable@f88b2837a7 (2026-08-18).
Data as JSON: /api/errors/76602c5f2a5e722d.
Report an issue: GitHub.
Appendix: source
Thrown at skill/scripts/live/manual-edits-buffer.mjs:38
export function getBufferPath(cwd = process.cwd()) {
return path.join(getLiveDir(cwd), BUFFER_FILENAME);
}
export function readBuffer(cwd = process.cwd()) {
return readBufferInternal(cwd, { strict: false });
}
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));
}
/**View on GitHub (pinned to f88b2837a7)