Why Error Handling Testing Matters
Users will inevitably encounter errors — they will visit deleted pages, submit invalid forms, experience network timeouts, and trigger server failures. How your application handles these errors determines whether users stay or leave, whether they trust your product, and whether attackers can exploit error responses.
Error handling is one of the most frequently overlooked testing areas. Developers focus on the happy path, and errors are often tested last (if at all). This creates opportunities for QA to find impactful bugs.
HTTP Status Code Categories
| Range | Category | Meaning |
|---|---|---|
| 2xx | Success | Request completed successfully |
| 3xx | Redirection | Client must take additional action |
| 4xx | Client Error | Request was invalid |
| 5xx | Server Error | Server failed to fulfill a valid request |
Key Status Codes to Test
| Code | Meaning | When to Test |
|---|---|---|
| 200 | OK | Every successful request |
| 301 | Moved Permanently | URL migrations, HTTPS redirects |
| 302/307 | Temporary Redirect | Login redirects, locale redirects |
| 400 | Bad Request | Malformed request data |
| 401 | Unauthorized | Missing or invalid authentication |
| 403 | Forbidden | Valid auth but insufficient permissions |
| 404 | Not Found | Non-existent URLs |
| 405 | Method Not Allowed | Wrong HTTP method (GET vs POST) |
| 408 | Request Timeout | Slow requests |
| 429 | Too Many Requests | Rate limiting |
| 500 | Internal Server Error | Unhandled server exceptions |
| 502 | Bad Gateway | Upstream server failures |
| 503 | Service Unavailable | Maintenance, overload |
| 504 | Gateway Timeout | Upstream server timeout |
Testing Custom Error Pages
404 Not Found Page
The most common error users encounter. Test that:
- Visiting a non-existent URL shows a custom 404 page (not a generic server error)
- The page maintains site branding (header, footer, styles)
- Navigation is available to help the user find what they need
- A search bar is present
- Links to popular pages or the homepage are provided
- The correct 404 HTTP status code is returned (not 200)
- The page works in all supported languages
500 Internal Server Error Page
- A friendly message is shown without technical details
- No stack traces, database errors, or file paths are visible
- Contact information or support link is provided
- The page suggests trying again later
- Monitoring/alerting triggers on 500 errors
403 Forbidden Page
- Explains that access is denied without revealing why (do not say “this resource belongs to another user”)
- Suggests logging in if the user is not authenticated
- Provides a link to request access if applicable
Maintenance Page (503)
- Clear message about maintenance in progress
- Expected return time if known
- Contact information for urgent issues
- Works without JavaScript (the app may be completely down)
Form Validation Error Testing
Client-Side Validation
| Scenario | Expected Behavior |
|---|---|
| Required field empty | “This field is required” near the field |
| Invalid email format | “Please enter a valid email address” |
| Password too short | “Password must be at least 8 characters” |
| Mismatched passwords | “Passwords do not match” |
| Invalid date | “Please enter a valid date” |
| Number out of range | “Value must be between X and Y” |
Server-Side Validation
Client-side validation can be bypassed. Test that:
- Disabling JavaScript and submitting forms still shows validation errors
- Submitting requests directly via API returns proper error messages
- Error messages do not reveal system internals
Error Message Quality
Good error messages:
- Tell the user what went wrong
- Tell the user how to fix it
- Are positioned near the problematic field
- Are announced to screen readers (using
aria-liveorrole="alert") - Do not disappear too quickly
Bad error messages:
- “An error occurred” (too vague)
- “Error code: NullPointerException at UserService.java:142” (too technical)
- “Invalid input” (does not say what is invalid or how to fix it)
Security Considerations
What Error Responses Must NOT Reveal
| Danger | Example |
|---|---|
| Stack traces | java.lang.NullPointerException at com.app.UserService.getUser(UserService.java:142) |
| Database errors | ERROR: column "email" of relation "users" does not exist |
| File paths | FileNotFoundException: /var/www/app/config/database.yml |
| Server versions | Apache/2.4.41 (Ubuntu) Server |
| Internal IPs | Connection refused to 10.0.1.42:5432 |
Error Enumeration Prevention
- Login errors should say “Invalid email or password” (not “Email not found” or “Wrong password”)
- Registration should not confirm whether an email is already in use
- Password reset should not confirm whether an email exists in the system
Exercise: Error Handling Audit
Test the error handling of a web application across all major error categories.
Part 1: HTTP Error Pages
| Test | URL/Action | Expected | Actual | Status |
|---|---|---|---|---|
| 404 page | Visit /nonexistent-page-xyz | Custom 404 with navigation | ||
| 404 returns correct status | Check response code | HTTP 404 (not 200) | ||
| 404 in other languages | Visit /es/nonexistent-page | 404 in correct language | ||
| 403 page | Access admin without auth | Custom 403 or redirect to login | ||
| 500 page | Trigger server error | Custom 500 without stack trace |
Part 2: Form Validation
Choose a form (registration, checkout, or contact) and test:
| Input | Value | Expected Error Message |
|---|---|---|
| empty | “Email is required” | |
| “not-an-email” | “Please enter a valid email” | |
| existing email | “An account with this email already exists” (or neutral message) | |
| Password | “123” | “Password must be at least 8 characters” |
| Password | “password” | Weak password warning |
| Phone | “abc” | “Please enter a valid phone number” |
| Required field | skip it | “This field is required” |
Part 3: Error Message Security
| Check | Pass/Fail |
|---|---|
| No stack traces in any error response | |
| No database error messages visible to users | |
| No file paths in error responses | |
| No server version in headers or error pages | |
| Login error does not reveal if email exists | |
| API errors return generic messages |
Solution: Common Error Handling Bugs
Bug 1: 404 page returns HTTP 200 The custom 404 page was served with a 200 status code. Search engines indexed “not found” pages as real content. Fix: Ensure the server returns HTTP 404 status with the custom page.
Bug 2: Stack trace visible on production 500 error A server error revealed the full Java stack trace including class names, method names, and line numbers. Fix: Configure production to show a generic error page and log details server-side only.
Bug 3: Form validation errors disappeared on scroll Validation errors at the top of a long form disappeared when the user scrolled down to fix the issue. Fix: Keep errors visible and scroll to the first error on submit.
Bug 4: Login reveals email existence “No account found with this email” on login reveals that the email is not registered, helping attackers enumerate valid accounts. Fix: Use “Invalid email or password” for all login failures.
Bug 5: API error returns SQL query
A malformed API request returned: ERROR: syntax error at or near "DROP" at character 42. Fix: Catch database errors and return generic API error messages.
Bug 6: Error page has no navigation The 404 page showed only “Page not found” with no links, header, or search. Users had to manually type the URL. Fix: Include full site navigation on error pages.
Automation for Error Handling
test('404 page returns correct status code', async ({ page }) => {
const response = await page.goto('/this-page-does-not-exist');
expect(response.status()).toBe(404);
await expect(page.locator('nav')).toBeVisible(); // Navigation present
await expect(page.locator('a[href="/"]')).toBeVisible(); // Home link
});
test('API errors do not leak internals', async ({ request }) => {
const response = await request.get('/api/users/invalid-id');
const body = await response.json();
expect(body.message).not.toContain('Exception');
expect(body.message).not.toContain('.java');
expect(body.message).not.toContain('SELECT');
});
Key Takeaways
- Error handling is frequently undertested — make it a standard part of your test plan
- Custom error pages should maintain site branding and provide navigation options
- Error messages must be user-friendly: explain the problem and how to fix it
- Never expose technical details in production error responses — stack traces, SQL, file paths
- Prevent information leakage through error responses (login enumeration, email existence)
- Verify that HTTP status codes match the error type (404 should return 404, not 200)