Testing Validation Errors: The Most Neglected Test Category
Most API bugs live in input validation. Here's how to test it systematically.
Why validation testing matters
Look at any API bug tracker: the majority of real production incidents trace back to one of three things:
- Input the server wasn't expecting.
- A validation rule that changed silently.
- An error response shape that clients couldn't parse.
All three are validation concerns. And all three are under-tested in most suites, because happy-path tests are more fun to write.
The validation surface
Every input field on every endpoint has a set of rules:
- Type — string, int, bool, date, enum, object, array.
- Presence — required vs optional.
- Format — email, UUID, ISO 8601, regex.
- Range — min/max for numbers, min/max length for strings, min/max items for arrays.
- Enumeration — allowed values for string fields.
- Cross-field — "if country is US, state is required."
- Uniqueness — email must not already exist.
- Ownership — the
user_idin the body must match the authenticated user.
Every one is a place to fail. Every one needs a test.
Try some bad inputs
/api/v1/userscurl -X POST 'https://demo.totalshiftleft.ai/api/v1/users' \
-H 'Content-Type: application/json' \
-d '{"name":"A","email":"not-an-email"}'Expected response:
{
"success": false,
"error": "VALIDATION_ERROR",
"message": "Validation failed",
"details": [
{ "field": "name", "code": "too_short", "message": "Must be at least 2 characters" },
{ "field": "email", "code": "invalid_format", "message": "Not a valid email address" }
]
}
Now send an empty body:
/api/v1/userscurl -X POST 'https://demo.totalshiftleft.ai/api/v1/users' \
-H 'Content-Type: application/json' \
-d '{}'Expected:
{
"success": false,
"error": "VALIDATION_ERROR",
"message": "Validation failed",
"details": [
{ "field": "name", "code": "required" },
{ "field": "email", "code": "required" }
]
}
The error envelope contract
The shape of the error response is as important as the shape of the success response. Clients parse it to show field-level errors to users. If it's inconsistent, UIs break.
Test every validation error for:
- HTTP status is 400 (or 422 if the API uses "Unprocessable Entity" for validation specifically).
- Top-level error code is a stable string (
VALIDATION_ERROR, not"Validation failed."). details(or equivalent) is an array of per-field errors.- Each detail has
field,code, and optionallymessage. fieldis a path (e.g.,user.address.postal_code), not just a flat name.codeis machine-readable (too_short,invalid_format), not human copy.
Once you've locked this down, every new endpoint should return errors in the same shape. That's contract.
The validation test matrix
For every string field, test:
- Missing (required check).
- Empty string (
"") — is this treated as missing or as invalid? - Whitespace-only (
" ") — trimmed? accepted? rejected? - Under min-length.
- Over max-length.
- Exactly at min and max (boundary).
- Invalid format (e.g., email without
@). - Valid format but semantically wrong (a valid-looking but non-existent country code).
- Non-string value (number, null, array) — type coercion or error?
For every number field:
- Missing.
- Zero (often an edge case: "0 is falsy").
- Negative.
- Below min.
- Above max.
- Boundaries (exactly min, exactly max).
- Non-integer where integer expected (e.g.,
1.5). - Scientific notation (
1e5) — does it parse? - String that looks like a number (
"123") — coerced or rejected?
For every enum field:
- Valid value.
- Invalid value.
- Wrong case (
"ACTIVE"when enum is"active"). - Null.
For every array field:
- Empty array.
- Array with min items.
- Array with max items + 1.
- Array with one invalid item.
- Array with duplicates (if uniqueness is required).
For every object field:
- Missing required sub-fields.
- Unknown sub-fields (should they be rejected or ignored?).
- Deeply nested invalid values.
Cross-field validation
The most forgotten class. Examples:
- "If country is 'US', state is required."
- "If role is 'admin', department must not be null."
- "end_date must be >= start_date."
Tests:
- All fields valid → 200.
- Country 'US' + missing state → 400, error on
state. - Country 'UK' + missing state → 200 (not required).
- end_date before start_date → 400, error on
end_date.
These rules are often implemented by hand and decay first. Always test them.
Validation from the AI angle
Hand-writing this matrix for even a small API (20 endpoints × 10 fields each) is hundreds of test cases. Nobody writes them all. That's why most APIs leak validation bugs.
AI-generated validation tests read the OpenAPI or GraphQL schema, derive the matrix automatically, and fuzz every boundary. ShiftLeft's validation generator produces ~20 test cases per field in a couple of seconds, with assertions on both the happy path and the error-envelope shape.
Common mistakes in validation tests
1. Only testing the happy path. Covered everywhere, but worth repeating.
2. Asserting on human-readable error messages. "Email is invalid" becomes "Email address is invalid" in a copy update and every test fails. Assert on code, not message.
3. Testing one field at a time. What if two fields are invalid simultaneously? Does the server return both errors or short-circuit? Your tests should establish which and assert on it.
4. Ignoring silent coercion. Server accepts "123" for an int field, tests pass. But what it actually does is silently cast — now "123abc" becomes 123, and the user's typo goes undetected. Test that type-wrong inputs 400, not 200.
5. Not testing the envelope itself. Spin up a test that hits 10 different endpoints with bad input, and assert they all return the same shape. Shape drift is a real bug.
What's next
Validation covers "what if the client sends something weird." Retries and timeouts covers "what if the network or server misbehaves."
That completes API 101. To keep going, the API testing hub has the full guides, and contract testing is the natural next topic: it turns the error envelope above into a checked contract. To practice on your own APIs, get the Free Developer License.
Frequently asked questions
What negative test cases should cover an API string field?+
Test the field missing, as an empty string, whitespace-only, under and over its length limits, exactly at the boundaries, with an invalid format, with a valid format that is semantically wrong, and as a non-string value such as a number, null, or array.
Should an API return 400 or 422 for validation errors?+
Either works. Most APIs use 400, and some use 422 Unprocessable Entity specifically for validation. What matters is consistency: the response should carry a stable top-level error code and a details array with field, code, and optional message for each failure.
What negative scenarios should cross-field validation tests cover?+
Cross-field rules depend on combinations, such as state being required only when country is US, or end_date needing to be on or after start_date. Test the valid combination, each violating combination with the error on the right field, and the case where the rule does not apply.
Related lessons
The network is unreliable. Here's how clients should retry, how servers should behave, and how to test both.
Happy paths prove your API works. Negative paths prove it fails safely. Here are the seven categories, a worked example, and where AI generation helps.
2xx means success, 4xx means you messed up, 5xx means they messed up — but the details matter. Here's the list every tester should know by heart.
Read more on the blog
What API schema validation is, how to validate requests and responses against an OpenAPI contract in tests, in CI and at the API gateway, the tools that do it (Ajv, Schemathesis, Prism, REST Assured, Postman), and how to catch schema drift.
API contract testing verifies that providers and consumers honor a shared interface contract (an OpenAPI schema or a Pact consumer contract), so breaking changes are caught in the pull request and services can deploy independently. Examples, approaches, a CI workflow and tools.