pbakaus/impeccable · error · Error
Invalid IMPECCABLE_LIVE_COPY_AGENT_MOCK_WRITES JSON
Error message
Invalid IMPECCABLE_LIVE_COPY_AGENT_MOCK_WRITES JSON
What it means
Thrown by applyMockWrites() when IMPECCABLE_LIVE_COPY_AGENT_MOCK_WRITES is set but does not parse into a plain object (it is JSON null, a primitive, or an array). The mock-writes var maps relative file paths to string contents that the mock runner writes under cwd; only an object map is meaningful.
Source
Thrown at skill/scripts/live-copy-edit-agent.mjs:517
const parsed = parseCopyEditBatchResult(raw);
if (parsed) return parsed;
throw new Error('Invalid IMPECCABLE_LIVE_COPY_AGENT_MOCK_RESULT JSON');
}
return {
status: 'done',
appliedEntryIds: (batch?.entries || []).map((entry) => entry.id).filter(Boolean),
failed: [],
files: [],
notes: ['mock copy-edit batch result'],
};
}
function applyMockWrites(env, cwd) {
const raw = env.IMPECCABLE_LIVE_COPY_AGENT_MOCK_WRITES;
if (!raw) return;
const writes = tryParseJson(raw);
if (!writes || typeof writes !== 'object' || Array.isArray(writes)) {
throw new Error('Invalid IMPECCABLE_LIVE_COPY_AGENT_MOCK_WRITES JSON');
}
for (const [relativeFile, content] of Object.entries(writes)) {
if (typeof relativeFile !== 'string' || typeof content !== 'string') continue;
const absolute = path.resolve(cwd, relativeFile);
if (!isPathInsideOrEqual(cwd, absolute)) continue;
fs.mkdirSync(path.dirname(absolute), { recursive: true });
fs.writeFileSync(absolute, content, 'utf-8');
}
}
export function parseCopyEditAgentResult(text) {
const trimmed = String(text || '').trim();
if (!trimmed) return null;
const parsedOuter = tryParseJson(trimmed);
if (parsedOuter) {
if (typeof parsedOuter.result === 'string') {
const nested = parseCopyEditAgentResult(parsedOuter.result);View on GitHub (pinned to d14711ae3d)
Solutions
- Provide a JSON object mapping relative paths to string contents, e.g. {"src/copy.txt":"Hello"}.
- Validate with `echo "$IMPECCABLE_LIVE_COPY_AGENT_MOCK_WRITES" | jq 'type'` — it must report "object".
- Unset the var if you do not need mock file writes.
Example fix
// before
export IMPECCABLE_LIVE_COPY_AGENT_MOCK_WRITES='["src/copy.txt"]'
// after
export IMPECCABLE_LIVE_COPY_AGENT_MOCK_WRITES='{"src/copy.txt":"Hello"}' Defensive patterns
Strategy: try-catch
Validate before calling
function parseMockWrites(raw) {
if (!raw) return {};
let obj;
try { obj = JSON.parse(raw); } catch { throw new Error('IMPECCABLE_LIVE_COPY_AGENT_MOCK_WRITES is not valid JSON'); }
if (!obj || typeof obj !== 'object' || Array.isArray(obj)) {
throw new Error('mock writes must be a JSON object of path -> string');
}
return obj;
} Type guard
function isMockWritesObject(raw) {
if (!raw) return true;
try {
const o = JSON.parse(raw);
return o && typeof o === 'object' && !Array.isArray(o);
} catch { return false; }
} Try / catch
try {
const writes = JSON.parse(process.env.IMPECCABLE_LIVE_COPY_AGENT_MOCK_WRITES);
if (Array.isArray(writes)) throw new Error('expected object');
} catch (err) {
console.error('Fix IMPECCABLE_LIVE_COPY_AGENT_MOCK_WRITES:', err.message);
} Prevention
- Use jq to confirm the value is type "object".
- Build the map in code and JSON.stringify it rather than hand-writing.
When it happens
Trigger: Setting IMPECCABLE_LIVE_COPY_AGENT_MOCK_WRITES to a JSON array, a bare string, a number, or malformed JSON. Each entry's key and value must both be strings; non-string entries are skipped silently but a non-object top level throws.
Common situations: Building the writes map programmatically and serializing an array by mistake; quoting the JSON so it arrives as a stringified string rather than an object.
Related errors
- Invalid IMPECCABLE_LIVE_COPY_AGENT_MOCK_RESULT JSON
- No live copy-edit AI runner is available.
- No live copy-edit AI runner is available.
- Unsupported live copy-edit AI runner: ${provider}
- AI copy-edit batch did not return a valid completion payload
AI-assisted analysis of pbakaus/impeccable@d14711ae3d (2026-08-13).
Data as JSON: /api/errors/f67a5a9dd789ca7b.
Report an issue: GitHub.