A validation error is part of the product interface, even when it first appears as JSON. It tells an application what happened and tells a person what to do next. When those audiences receive the same unstructured sentence, the result can be fragile client logic and confusing copy. A better contract separates transport behavior, stable machine-readable reasons, and the explanation shown to the user.

This guide proposes an error design that handles incomplete input, ambiguous findings, unavailable checks, and unexpected failures without treating them as the same problem. The examples are design patterns, not a description of a live ValidAPI endpoint or an operational service guarantee.

Separate request errors from validation findings

A malformed request is different from a successfully processed request whose subject needs correction or review. Decide how the API distinguishes them. An unsupported media type belongs to the request contract, while a completed address check with an unresolved unit belongs to the domain result. Clients should not need to infer the layer from a sentence that may change when the documentation is edited.

Keep the HTTP outcome and the domain outcome visible together. A successful HTTP response does not mean every check passed. A temporary service failure does not mean the submitted information is false. Make both distinctions explicit in examples, tests, and public copy. This prevents an operational outage from being translated into an accusation about the user's record simply because the interface only knows two colors.

Use an established problem envelope where useful

RFC 9457, Problem Details for HTTP APIs defines a machine-readable structure for HTTP problems. Its members include a problem type, title, status, detail, and instance, with extension members available for additional information. It is a useful starting point for request and operational errors without requiring every integration to invent an unrelated envelope with different names for the same concepts.

An envelope does not define the application's entire policy. You still need stable problem types, documented extensions, disclosure rules, and a distinction between errors and completed validation results. Field-level correction information can be an extension in a proposed design. Specify its shape and test it instead of allowing arbitrary internal exception objects to become the public interface whenever an unexpected case occurs.

Give reason codes stable meanings

Choose codes around observations and actions. country_required is more useful than bad_input, while provider_unavailable is more accurate than invalid_identity when a dependency timed out. Document whether each reason is retryable, user-correctable, or reviewable. Keep that classification consistent across clients so the same observation does not produce contradictory instructions in the mobile app and the website.

Do not require clients to parse the human-readable message to choose behavior. Copy can change for clarity or translation. A stable code should carry the behavior, while the message explains it. The proposed response model illustrates how status, reasons, and next action can coexist without collapsing all outcomes into a boolean that loses the information needed for recovery.

Point to the field without echoing its value

When an issue concerns a field, return a documented field reference so the interface can associate the message with the correct control. Avoid including the entire submitted value just to identify that location. A path and reason are often enough for a correction prompt without placing a document number or contact detail into errors, logs, dashboards, and support messages.

Keep field issues independently actionable

If several fields need attention, retain the relationship between each field and its reason. Decide whether the API returns all safely disclosable issues at once or stops at a defined stage. Document that behavior. The interface should not promise that fixing the first visible issue will complete every remaining check when some checks have not yet been attempted or require another stage of the workflow.

Make uncertainty a supported result

Create explicit domain states for unsupported context, missing evidence, and partial matches. Each can lead to a different action. Preserve what is known and what remains unresolved. Do not make consumers interpret an absent field as not applicable, not checked, or failed depending on undocumented circumstances. That ambiguity tends to spread as additional clients are developed by teams with different assumptions.

Specify aggregation rules for mixed results. An optional format check may pass while a required source comparison is unavailable. The workflow might need to pause, but that is not a reason to overwrite the successful observation. Keep individual findings separate from the next action so the application can explain why the journey cannot yet continue without suggesting that every submitted field was wrong.

Write public messages around recovery

A useful message explains what needs attention and which action is available. “Add the country for this number” is actionable when country context is missing. “We could not complete this check” fits a temporary unavailable state. Use each only when it describes the actual observation. Familiar wording is not helpful when it sends the person toward an action that cannot resolve the problem.

Avoid blame, unexplained codes, and certainty the system does not possess. A comparison mismatch should follow the approved review process, not become a claim that someone is fraudulent. Internal diagnostics may contain a narrower reason where appropriate, while public copy remains truthful and proportionate. Withhold sensitive detail deliberately rather than replacing it with an explanation that is simpler but materially misleading.

Specify retry behavior instead of hoping

Document which failures may be retried and under what limits. A corrected request is different from an automatic repeat after a timeout. Decide how clients handle duplicate submissions, late responses, and checks that complete after the user has moved on. Associate results with the submitted input and workflow state so a delayed success is not accidentally applied to a newer value.

Avoid indefinite retries. Define a bounded retry budget and a final unavailable state that the interface can explain. Do not repeatedly retry missing required fields without a relevant change. Test the policy for each retryable reason, including the point at which automatic attempts stop. A retry rule belongs in the contract and client design, not as an unreviewed loop added to conceal an intermittent error.

Keep observability useful and narrow

An error event can often contain the request identifier, route, status, reason, duration, and policy version without copying the subject's data. Define a logging allowlist and review exception handlers that may include raw request content. A careful response design can be undermined by middleware that captures every failed payload, especially when those logs are shipped to another system with different access controls.

Separate the information the caller needs from the information an authorized operator needs. Neither audience automatically needs every internal detail. Keep credentials, document numbers, and unrelated attributes out of public errors. The data-minimization guide describes how to design diagnostics as a bounded operational tool instead of a second, less visible store of personal records.

Test errors as a complete interface

Create fixtures for malformed JSON, missing context, unsupported inputs, partial findings, dependency failures, and unexpected exceptions. Assert the transport status, response shape, reason, next action, and public message. Include unknown future codes: a client should have a safe fallback instead of crashing or assuming success because it does not recognize a value introduced by a later provider update.

Then test the recovery sequence. Does editing a field clear the relevant issue without hiding unrelated ones? Can an old response reintroduce a resolved error? Can the person reach the correction using a keyboard? Does the page retain useful context after an outage? These questions expose problems that a schema-only test misses because they concern behavior across a series of actions, not one static response.

Conclusion: errors are documented outcomes

A good validation API treats errors and uncertainty as first-class outcomes. It separates request problems from findings, uses stable reasons, protects unnecessary detail, and offers a truthful next step. The API and the interface should tell the same story at different levels of detail rather than making different claims about the same event.

Write failure examples before polishing the happy path. When each unresolved state has a defined meaning and recovery route, implementation becomes easier to review, clients become less brittle, and support teams spend less time translating an unexplained invalid message into something the person can actually act on.