By Sagar Shankaran, Founder of CallSphere
The failure modes of Claude batch jobs — silent drops, cost runaway, poisoned outputs — and concrete patterns to contain blast radius and recover safely.
Key takeaways
A batch job is a loaded weapon pointed at your own data. That sounds dramatic until the first time one misfires. A single wrong instruction, replicated across 800,000 requests, does not produce one bad answer — it produces 800,000 bad answers, written confidently into a table your downstream systems already trust. By the time anyone notices, the bad data has fanned out into dashboards, emails, and decisions. The Message Batches API is wonderful precisely because it removes the human from the loop; risk management is the discipline of earning the right to remove that human safely.
This post is a field guide to what actually goes wrong in production batch jobs on Claude, ranked roughly by how often I have seen each bite teams, with containment patterns for each. The framing throughout is blast radius: not "can this fail?" but "when it fails, how many rows, how much money, and how far does the damage travel before someone catches it?"
Most batch incidents are one of a small set. Knowing them by name lets you design the specific guardrail rather than a vague "add monitoring."
1. Silent partial drops. The job ends with a mix of succeeded, errored, and expired requests, and your reconciliation only reads the succeeded ones. The errored rows quietly fall out of the dataset. This is the most common and most damaging failure because there is no alarm — the numbers just look slightly off.
2. Poisoned prompt template. A bug in the prompt you assemble (a wrong column, a stray instruction, a broken delimiter) is replicated across every row. The model dutifully follows it. Blast radius equals the whole batch.
3. Cost runaway. An oversized prompt, an unbounded max_tokens, or an accidental re-submission multiplies spend. Batches amortize cost beautifully and overspend just as efficiently.
4. Schema drift in outputs. The model returns mostly-valid JSON with occasional malformed rows. Naive parsing either crashes or, worse, coerces garbage into your columns.
Hear it before you finish reading
Talk to a live CallSphere AI voice agent for home services in your browser — 60 seconds, no signup.
5. Stale or wrong source mapping. Results land back on the wrong rows because the custom_id mapping was rebuilt or reordered between submit and fetch.
6. Expiry and timeout. Long jobs hit the batch window and a tail of requests expires unprocessed. If you do not detect and requeue them, they are simply lost.
7. Prompt-injection via source data. When your input rows contain user-generated text, that text can carry instructions. At batch scale, an injection that flips behavior runs unattended across many rows.
The diagram below is the decision path I want every batch job to follow when a result comes back. The point is that nothing reaches the system of record without passing a gate.
flowchart TD
A["Batch result row"] --> B{"Status == succeeded?"}
B -->|No| Q["Quarantine + requeue"]
B -->|Yes| C{"Schema & ranges valid?"}
C -->|No| Q
C -->|Yes| D{"Within canary tolerance?"}
D -->|No| H["Halt batch, page owner"]
D -->|Yes| E["Write to staging table"]
E --> F["Reconcile to source by custom_id"]
Two things make this safe. First, the canary check: you run a small slice (say the first 1–2% of rows) and compare its error rate and output distribution against expectations before releasing the rest. If the canary is off, you halt before the other 98% executes. Second, the staging table: results never write directly to the system of record. They land in staging, get reconciled, and only then promote — which means every write is reversible.
Canary before full volume. Submit a representative 1–2% slice, grade it, and gate the full run on the canary passing. This single pattern catches poisoned templates and schema drift before they replicate. The cost of the canary is a rounding error against the cost of re-doing a million rows.
Hard cost ceiling. Before submitting, compute the worst-case spend (max input tokens + capped max_tokens, times row count, times price) and refuse to launch if it exceeds a threshold you set on purpose. Treat an unexpected estimate as a bug, not a surprise to absorb.
Treat output as untrusted. Validate every field's type and range. The snippet below is the minimal gate I put between fetched results and any write.
Still reading? Stop comparing — try CallSphere live.
See the home services AI agent handle a real call — complete, industry-specific, and live in your browser. No signup.
def safe_promote(result):
try:
data = json.loads(result["message"]["content"][0]["text"])
except (KeyError, ValueError):
return quarantine(result, "unparseable")
if data.get("label") not in {"pos", "neg", "neutral"}:
return quarantine(result, "bad_label")
score = data.get("score")
if not isinstance(score, (int, float)) or not 0 <= score <= 1:
return quarantine(result, "bad_score")
return staging_write(result["custom_id"], data) # reversible by custom_id
Anything that fails goes to quarantine with a reason, never into the system of record. Quarantined rows are visible, countable, and requeueable — which converts a silent drop into a loud, recoverable event.
| Failure mode | Without control | With control |
|---|---|---|
| Poisoned template | Whole batch corrupted | Canary halts at ~1% |
| Silent partial drop | Rows vanish unnoticed | Quarantine count alarms |
| Cost runaway | Surprise on invoice | Pre-launch ceiling refuses |
| Bad write to prod | Manual cleanup, downtime | Reverse via staging table |
The teams that recover gracefully from a bad batch are the ones that rehearsed it. Treat batch reliability like incident response: run a game day where you deliberately inject each failure mode against a staging copy and confirm your controls catch it. Corrupt one column in the prompt template and verify the canary halts. Drop a chunk of results and verify the count reconciliation alarms. Submit an input row laced with an injected instruction and verify the output validation flags that the row went off-task. Each drill that passes is a control you can trust at 3 a.m.; each drill that fails is a gap you found cheaply.
Write the recovery runbook while the system is calm, not during the incident. It should answer three questions for any failure: how do I stop the bleeding (halt and stop further writes), how do I assess the damage (count affected rows by custom_id), and how do I reverse it (roll back the staging promote for exactly those IDs). Because every write is keyed by a stable ID and staged, all three answers are mechanical rather than heroic. The blast radius of a batch is only as small as your ability to enumerate and undo the rows it touched.
custom_id and promote.The silent partial drop. Errored or expired requests fall out of the result set, and if your reconciliation only reads successes, those rows vanish with no alarm. Always reconcile total counts so a drop becomes a loud, recoverable event.
Compute worst-case spend before launch — max input tokens plus a capped max_tokens, times the row count, times price — and make the job refuse to start if it exceeds a deliberate ceiling. Cap max_tokens on every request so no single response can run away.
Almost always. A 1–2% canary catches poisoned templates and schema drift for a tiny fraction of the full cost, before the other 98% replicates the mistake. It is the highest-leverage control in batch work.
Never write directly to the system of record. Write to a staging table keyed by stable custom_ids, reconcile, then promote. Because the IDs are stable, you can always identify and roll back exactly the rows a bad batch touched.
The same containment thinking — canaries, quarantines, reversible writes — keeps CallSphere's voice and chat agents safe as they answer calls, call tools mid-conversation, and book work at scale. Explore it at callsphere.ai.
Source & attribution: This is an independent, original explainer inspired by Anthropic's coverage on the Claude blog. Claude, Claude Code, Claude Cowork, Claude Opus, and the Model Context Protocol are products and trademarks of Anthropic. CallSphere is not affiliated with or endorsed by Anthropic.

Written by
Sagar Shankaran· Founder, CallSphere
LinkedInSagar Shankaran is the founder of CallSphere, where he builds production AI voice and chat agents deployed across healthcare, hospitality, real estate, and home services. He writes about agentic AI, LLM engineering, and shipping voice agents that handle real calls in production.
See how AI voice agents work for your industry. Live demo available -- no signup required.
Anthropic's Claude Fable 5 and Mythos 5 explained: pricing, availability, frontier benchmarks, the dual-model safeguard architecture, and what they mean for AI agents.
Copied DARs, clustered tour hits and injury language sit unread in 8,400 reports a month. Here is the 2026 arithmetic that makes reading all of them economic.
Where Claude Code, MCP, and multi-agent systems are taking GTM engineering next, and how to prepare your team now for standing and multi-agent workflows.
Where Claude Cowork and the Claude agent ecosystem are heading next — standing agents, MCP, skills as a moat — and the concrete moves to prepare your team now.
The metrics, leading signals, and anti-metrics that prove Claude Cowork is working — acceptance rate, time-to-outcome, and why usage counts mislead.
Shipping an agentic GTM workflow is easy; proving it works is hard. The metrics, signals, and eval loops that show a Claude Code rebuild is paying off.
© 2026 CallSphere Inc. All rights reserved.
Made within San Francisco
Watch how CallSphere handles real customer calls, schedules appointments, and processes payments — live.
Try Live DemoBook a DemoCalculate Your ROI