{"record":{"id":"7046619b1b1a30a0","repo":"pbakaus/impeccable","slug":"ai-copy-edit-batch-did-not-return-a-valid-completi-704661","errorCode":null,"errorMessage":"AI copy-edit batch did not return a valid completion payload. ${tail.trim()}","messagePattern":"AI copy-edit batch did not return a valid completion payload\\. (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"skill/scripts/live-copy-edit-agent.mjs","lineNumber":136,"sourceCode":"  const outDir = opts.outDir || fs.mkdtempSync(path.join(os.tmpdir(), 'impeccable-copy-batch-'));\n  fs.mkdirSync(outDir, { recursive: true });\n  const resultPath = path.join(outDir, 'result.json');\n  const logPath = path.join(outDir, 'agent.log');\n\n  if (provider === 'codex') {\n    await runCodex(prompt, { cwd, env, resultPath, logPath, timeoutMs: opts.timeoutMs });\n  } else if (provider === 'claude') {\n    await runClaude(prompt, { cwd, env, resultPath, logPath, timeoutMs: opts.timeoutMs });\n  } else {\n    throw new Error(`Unsupported live copy-edit AI runner: ${provider}`);\n  }\n\n  const output = fs.existsSync(resultPath) ? fs.readFileSync(resultPath, 'utf-8') : '';\n  const parsed = parseCopyEditBatchResult(output);\n  if (parsed) return parsed;\n\n  const tail = fs.existsSync(logPath) ? fs.readFileSync(logPath, 'utf-8').slice(-1200) : output.slice(-1200);\n  throw new Error('AI copy-edit batch did not return a valid completion payload. ' + tail.trim());\n}\n\nexport function runCopyEditPostApplyChecks({ cwd = process.cwd(), files = [] } = {}) {\n  const failures = [];\n  const warnings = [];\n  const uniqueFiles = [...new Set((files || []).filter((file) => typeof file === 'string' && file.trim()))];\n  for (const relativeFile of uniqueFiles) {\n    const file = path.resolve(cwd, relativeFile);\n    if (!isPathInsideOrEqual(cwd, file) || !fs.existsSync(file)) {\n      warnings.push({ file: relativeFile, reason: 'file_missing_or_outside_cwd' });\n      continue;\n    }\n    let content = '';\n    try { content = fs.readFileSync(file, 'utf-8'); } catch (err) {\n      failures.push({ file: relativeFile, reason: 'read_failed', message: err.message });\n      continue;\n    }\n    const markerMatch = findLeftoverImpeccableMarker(content);","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/pbakaus/impeccable/blob/d14711ae3d1a1dd62dee61a358d27f107c51ccd0/skill/scripts/live-copy-edit-agent.mjs#L118-L154","documentation":"Thrown by runCopyEditBatchAgent() after codex or claude ran to completion but neither result.json nor the captured output parses into a valid batch result (parseCopyEditBatchResult returned null, i.e. status was not done/partial/error). The message appends the last ~1200 chars of agent.log (or output) so the underlying model/CLI failure is visible.","triggerScenarios":"The CLI exited cleanly but wrote no valid JSON; the model returned prose without the expected status field; a timeout/parse mismatch left result.json empty or malformed; the model was cut off mid-payload.","commonSituations":"Weak model that ignores the JSON schema; rate-limit/auth error mid-run that the CLI logged but did not surface as a non-zero exit; a prompt too large for the context window; an outdated CLI output format.","solutions":["Read the tail included in the error — it usually contains the model/CLI reason (auth, rate limit, truncation).","Check <tmpdir>/impeccable-copy-batch-*/agent.log for the full transcript.","Retry with a stronger/larger model via IMPECCABLE_LIVE_COPY_AGENT_MODEL, or raise the timeout via opts.timeoutMs.","If the CLI itself is misbehaving, run `claude setup-token`/`codex login` again or switch provider with IMPECCABLE_LIVE_COPY_AGENT."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isValidBatchResult(r) {\n  return r && ['done', 'partial', 'error'].includes(r.status);\n}","tryCatchPattern":"try {\n  const result = await runCopyEditBatchAgent(batch, opts);\n  return result;\n} catch (err) {\n  if (/did not return a valid completion payload/.test(err.message)) {\n  // surface the agent.log tail, retry with a larger model/timeout, or fall back to mock\n    console.error('Copy-edit payload invalid:', err.message);\n    throw err;\n  }\n  throw err;\n}","preventionTips":["Pin a capable model via IMPECCABLE_LIVE_COPY_AGENT_MODEL.","Keep batches small so the response stays within the schema.","Inspect agent.log immediately on first failure."],"tags":["live-copy-edit","agent-runner","parse-error","provider"],"backgroundTag":null,"analyzedSha":"d14711ae3d1a1dd62dee61a358d27f107c51ccd0","analyzedAt":"2026-08-13T00:52:25.771Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}