Domain 4 of the Claude Certified Developer – Foundations (CCDV-F) exam, Eval, Testing, and Debugging, is the smallest domain on the blueprint at roughly 2.6% of the total weight, carried entirely by one sub-objective: Debugging and Error Handling.
This guide is an independent, unofficial study resource. It is not affiliated with, authorized by, or endorsed by Anthropic, and it reproduces no real exam items. Everything below is grounded in Anthropic's published API error semantics plus well-established general software testing and debugging practice applied to LLM applications.
Despite its small weight, this domain tests a skill that shows up constantly in production: correctly isolating which layer is actually failing from a single observed symptom. A user reports "the app gave a wrong answer" or "the request failed," and that one sentence is consistent with at least four structurally different root causes — a broken API call, a broken tool, a badly-fed prompt, or a genuinely bad model response. Treating all four as the same problem, or worse, misdiagnosing one as another, is the single most common debugging mistake in Claude applications — and it's exactly what this domain is built to test.
The four-layer failure-isolation framework
Every request through a Claude application passes through the same four layers, in order: the API call itself, any tools the model invokes, the prompt and context the model was given, and finally the model's own reasoning over all of that. A failure can originate at any one of these layers, but by the time it surfaces to a user or a log line, it often looks identical to a failure at a different layer. The exam-relevant skill is working backward from the symptom to the correct layer, not guessing based on which layer is easiest to blame.
- API-layer failures: auth errors, rate limits, malformed requests, or server-side errors. These are identifiable from the HTTP status code and error type in the response — not from anything about what Claude said, because at this layer Claude never got a chance to say anything.
- Tool-execution failures: the tool itself errored, returned wrong or stale data, or timed out. Claude only knows what the tool told it — if the tool is broken, no amount of prompt engineering will fix the output, because the model is reasoning correctly over bad input.
- Prompt/context problems: Claude wasn't given what it needed — missing context, ambiguous instructions, or context that rotted or drifted over a long session. The model is working correctly; the input it received was insufficient or unclear.
- Genuine model-output problems: Claude had everything it needed — correct tool results, clear instructions, sufficient context — and still produced a wrong or poorly-reasoned answer. This is the rarest category to correctly diagnose, and the one most often mis-blamed for failures that actually belong to one of the other three layers.
Decision table: symptom to layer to fix
Because the same surface symptom can map to multiple layers, the practical skill is checking evidence in a fixed order — status code and error type first, then tool_result blocks, then the prompt/context that was actually sent, and only then the model's reasoning itself. The table below is the shape of that check, mapped to typical exam-style scenarios.
| Symptom | Likely layer | What to check | Typical fix |
|---|---|---|---|
| Request fails immediately, no model output at all | API | HTTP status code and error type in the response body | Retry (429/500/504/529/network) or fix the request (400/401/403/404) — never retry a permanent error unchanged |
| Answer references data that's wrong, missing, or clearly outdated | Tool execution | is_error on the relevant tool_result block; the raw data the tool actually returned | Fix or replace the tool, add validation on tool output, or surface the tool error to the user instead of letting the model guess |
| Answer is vague, off-topic, or ignores instructions that were clearly stated | Prompt/context | The exact prompt and context sent on that turn, including anything trimmed by context management over a long session | Sharpen instructions, add missing context, or restructure a session that has drifted |
| Response is cut off mid-sentence or unexpectedly short | API signal, not model reasoning | stop_reason — an unexpectedly short answer with stop_reason: "max_tokens" is a token-budget problem, not a reasoning failure | Raise max_tokens or shorten the prompt — not rewording instructions |
| Model had correct tool results, clear instructions, sufficient context — and still reasoned incorrectly | Model output | Confirm the first three layers are actually clean before concluding this | Prompt refinement, a stronger model, or accepting the error rate as a known limitation — this is the last layer to blame, only after ruling out the other three |
Note the ordering: the table is deliberately sequenced from easiest-to-verify to hardest-to-verify. Status codes and error types are unambiguous and cheap to check. is_error on a tool_result is a structured, explicit signal. Prompt/context problems require reading what was actually sent, which takes more effort but is still mechanical. Genuine model-output problems require first confirming the other three layers are clean — which is exactly why that category is the rarest to correctly diagnose and the easiest to reach for prematurely.
stop_reason and is_error as diagnostic signals
Two structured fields carry most of the diagnostic weight in this domain, and both are frequently under-used in application logging: stop_reason on the response, and is_error on a tool_result content block.
stop_reason tells you why Claude stopped generating, and its possible values are themselves diagnostic categories rather than a single generic "done" flag: end_turn (a normal, complete response), max_tokens (the response was truncated by the token budget, not by the model deciding it was finished), stop_sequence (a configured stop sequence was hit), tool_use (Claude is pausing to call a tool and expects a tool_result back), pause_turn (a long-running turn paused and can be resumed), and refusal (the model declined to continue for policy reasons). Reading this field before reading the content of the response itself narrows the diagnosis immediately — a short, seemingly-incomplete answer with stop_reason: "max_tokens" is a token-budget problem with a mechanical fix, not evidence the model reasoned poorly.
is_error: true on a tool_result block is the specific, structured signal for a tool-layer failure. A well-built application surfaces this distinctly in its own logging and tracing rather than lumping every "the answer was wrong" case into one undifferentiated bucket. If tool errors and model-reasoning errors are logged identically, isolating the failing layer after the fact becomes guesswork instead of a lookup.
| Retryable (transient) | Permanent (never retry unchanged) |
|---|---|
| 429 (rate limit), 500, 504, 529, network errors | 400 (malformed request), 401 (auth), 402, 403 (forbidden), 404 (not found), 409 (conflict), 413 (payload too large) |
Deterministic vs. model-based evaluation, and regression discipline
Once a failure is correctly isolated and fixed, the next question this domain tests is how you know it's fixed — and stays fixed. That's an evals and testing question, and it splits into two complementary approaches.
- Deterministic tests — exact-match comparisons, schema validation, code-execution checks — apply wherever the task has a checkable, well-defined correct answer. Use these wherever the task allows a deterministic check; they're cheap, fast, and unambiguous.
- Model-based (LLM-as-judge) evaluation is for genuinely open-ended output where no deterministic check is possible — quality, tone, helpfulness, or correctness judgments that can't be reduced to an exact match or a schema. Reserve this approach for cases that actually need it, since it's more expensive and less precise than a deterministic check.
The general rule the exam expects: prefer a deterministic check whenever the task structure permits one, and fall back to model-based evaluation only for the open-ended remainder. Using an LLM judge where a schema check or exact-match test would suffice adds cost and noise without adding rigor.
Tracing and observability are what make layer-isolation possible after the fact, rather than only in the moment something breaks. Logging enough structured detail per request — which layer executed, what each tool actually returned, what stop_reason was on each turn, and latency per step — is what lets a debugging session start from evidence instead of speculation. A system that only logs the final answer cannot be debugged when something goes wrong later, because every layer's evidence except the last one is already gone.
Worked example: diagnosing "the assistant gave a wrong answer"
A support ticket comes in: a Claude-powered assistant told a customer their order had shipped when it had not. The surface symptom is identical to a genuine model-reasoning failure — the answer was simply wrong — so the instinct is often to rewrite the system prompt to be more careful about order status. That instinct skips the isolation step.
- Check the API layer first: was the request itself successful? Status 200, no auth or rate-limit error. Rule out the API layer.
- Check the tool layer next: the assistant called an
order_statustool for this request. The trace shows the tool_result block for that call — and it carriesis_error: false, but the returned payload showsstatus: "shipped"for an order that, per the shipping provider's own record, had not shipped yet. - Stop here. This is a tool-execution failure, not a model failure — the tool returned stale or incorrect data, and Claude reported exactly what the tool told it. The model reasoned correctly over bad input.
- Confirm by checking the prompt/context layer anyway, since it's cheap to rule out: the system prompt correctly instructed the assistant to report tool data as-is and flag uncertainty; no ambiguity contributed here.
- The fix is at the tool layer: investigate why
order_statusreturnedshippedprematurely — likely a caching or sync delay in the underlying order system — not a rewrite of the assistant's system prompt.
Key takeaways
- 01Every request passes through four layers — API, tool execution, prompt/context, and model reasoning — and the same surface symptom can originate at any of them. The fix has to match the layer that actually failed.
- 02Check evidence in a fixed, cheap-to-expensive order: HTTP status/error type first, then
is_erroron tool_result blocks, then the actual prompt/context sent, and only then consider genuine model reasoning. - 03
stop_reasonis diagnostic on its own: an unexpectedly short response withstop_reason: "max_tokens"is a token-budget problem fixed by raising the limit or shortening the prompt, not a reasoning failure. - 04
is_error: trueon a tool_result is the structured signal for a tool-layer failure and should be logged and traced distinctly from model-output failures, not lumped into one "wrong answer" bucket. - 05Retryable errors (429, 500, 504, 529, network) are transient; permanent errors (400, 401, 402, 403, 404, 409, 413) will just fail again unchanged — retry logic must respect this distinction.
- 06Use deterministic tests (exact-match, schema, code-execution) wherever the task allows one; reserve model-based/LLM-as-judge evaluation for genuinely open-ended output. Treat prompt changes with the same regression-testing discipline as code changes.
Common mistakes
Treating a tool-execution failure as a prompt problem and trying to prompt-engineer around a tool that is actually broken.
Check is_error and the raw tool_result payload before touching the prompt. If the tool returned wrong or stale data, no amount of instruction rewriting changes the output — fix or replace the tool instead.
Reading a short or truncated response as evidence of weak model reasoning.
Check stop_reason first. max_tokens means the response was cut off by the token budget, not that the model reasoned poorly — the fix is raising max_tokens or shortening the prompt, not rewording instructions.
Shipping a prompt or system-instruction change after only manually trying a few inputs, with no regression check against previously-working behavior.
Run the existing eval suite — deterministic checks plus any model-based evals in place — against the changed prompt before shipping, the same way a code change would be regression-tested.
Frequently asked
Why does this domain only carry 2.6% of the exam if failure isolation is such a common real-world skill?
The blueprint weights domains by breadth of tested content, not by how often the underlying skill matters in practice. Domain 4 covers one focused sub-objective — debugging and error handling — while domains like Agents and Workflows or Applications and Integration span multiple sub-objectives across more surface area. A small weight doesn't mean the material is unimportant, just that fewer exam items are drawn from it.
How do I tell a tool-layer failure apart from a model-output failure when both can produce a 'wrong answer'?
Check the tool_result block's is_error flag and its actual returned payload first. If the tool result was correct and complete and the model still reasoned incorrectly over it, that's a model-output failure. If the tool result itself was wrong, stale, or flagged as errored, the model was reasoning correctly over bad input — that's a tool-layer failure, and the model is not at fault.
When should I use LLM-as-judge evaluation instead of a deterministic test?
Only when the output is genuinely open-ended and no deterministic check applies — judging tone, helpfulness, or nuanced correctness that can't be reduced to an exact match or schema validation. Wherever a deterministic check is possible, prefer it: it's cheaper, faster, and unambiguous, and reserving LLM-as-judge for the open-ended remainder keeps the eval suite both rigorous and affordable.
Independent, unofficial study material. Not affiliated with, endorsed by, or authorized by Anthropic. Every example is original and written to teach the public exam objectives — no real exam questions are reproduced. Technical details reflect Claude, the Anthropic API, Claude Code, and MCP as of August 24, 2026; always confirm specifics against current official documentation.
Test yourself
Turn what you just read into answers you can check.