pbakaus/impeccable · error · Error
Unsupported live copy-edit AI runner: ${provider}
Error message
Unsupported live copy-edit AI runner: ${provider} What it means
Thrown by runCopyEditBatchAgent() when provider is truthy but not one of mock/chat/codex/claude. In practice this is unreachable through chooseCopyEditAgent() (which only returns those four or null), so it is only hit when a caller passes opts.provider directly with an unsupported string. It guards against a typo'd or future provider name silently running nothing.
Source
Thrown at skill/scripts/live-copy-edit-agent.mjs:128
const raw = await opts.applyBatchToSource(batch, { repair: batch?.repair || null });
return normalizeBatchResult(raw || {});
}
if (!provider) {
throw new Error(describeNoProviderError({ env }));
}
const prompt = buildCopyEditBatchPrompt(batch, { cwd });
const outDir = opts.outDir || fs.mkdtempSync(path.join(os.tmpdir(), 'impeccable-copy-batch-'));
fs.mkdirSync(outDir, { recursive: true });
const resultPath = path.join(outDir, 'result.json');
const logPath = path.join(outDir, 'agent.log');
if (provider === 'codex') {
await runCodex(prompt, { cwd, env, resultPath, logPath, timeoutMs: opts.timeoutMs });
} else if (provider === 'claude') {
await runClaude(prompt, { cwd, env, resultPath, logPath, timeoutMs: opts.timeoutMs });
} else {
throw new Error(`Unsupported live copy-edit AI runner: ${provider}`);
}
const output = fs.existsSync(resultPath) ? fs.readFileSync(resultPath, 'utf-8') : '';
const parsed = parseCopyEditBatchResult(output);
if (parsed) return parsed;
const tail = fs.existsSync(logPath) ? fs.readFileSync(logPath, 'utf-8').slice(-1200) : output.slice(-1200);
throw new Error('AI copy-edit batch did not return a valid completion payload. ' + tail.trim());
}
export function runCopyEditPostApplyChecks({ cwd = process.cwd(), files = [] } = {}) {
const failures = [];
const warnings = [];
const uniqueFiles = [...new Set((files || []).filter((file) => typeof file === 'string' && file.trim()))];
for (const relativeFile of uniqueFiles) {
const file = path.resolve(cwd, relativeFile);
if (!isPathInsideOrEqual(cwd, file) || !fs.existsSync(file)) {
warnings.push({ file: relativeFile, reason: 'file_missing_or_outside_cwd' });View on GitHub (pinned to d14711ae3d)
Solutions
- Pass one of the supported providers: 'mock', 'chat', 'codex', or 'claude'.
- Omit opts.provider to let chooseCopyEditAgent() pick automatically based on env/auth.
- If you are extending the runner, add the new branch in runCopyEditBatchAgent and a matching case in chooseCopyEditAgent.
Example fix
// before
runCopyEditBatchAgent(batch, { provider: 'gpt' });
// after
runCopyEditBatchAgent(batch, { provider: 'claude' }); Defensive patterns
Strategy: type-guard
Validate before calling
const SUPPORTED = new Set(['mock', 'chat', 'codex', 'claude']);
if (!SUPPORTED.has(provider)) {
throw new Error('Unsupported provider: ' + provider + '. Use one of ' + [...SUPPORTED].join(', '));
} Type guard
function isSupportedCopyEditProvider(p) {
return ['mock', 'chat', 'codex', 'claude'].includes(p);
} Prevention
- Do not hard-code provider names from outside the supported set.
- Omit opts.provider to use auto-selection.
When it happens
Trigger: Calling runCopyEditBatchAgent(batch, { provider: 'gpt' }) or any non-null string other than mock/chat/codex/claude. Programmatic callers that hard-code a provider name are the realistic source.
Common situations: A fork or integration that passes a custom provider string without updating the dispatch branch; a typo when forwarding opts.provider.
Related errors
- No live copy-edit AI runner is available.
- AI copy-edit batch did not return a valid completion payload
- 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/97edac53375cdc5b.
Report an issue: GitHub.