# Error messages specify exact requirement

- **Pattern:** `ab-001455` (`finserv-form-validation.error-edge-cases.error-clarity`)
- **Severity:** info
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001455
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001455)

## Why it matters

A validation error that says "Invalid input" tells the user nothing about what to change. In a financial form, that friction causes abandonment — and for accessibility, WCAG 2.2 SC 3.3.1 (Error Identification) and SC 3.3.3 (Error Suggestion) require that errors both identify what is wrong and suggest a correction. "Amount must be between $0.01 and $9,999.99" passes both; "Validation failed" fails both. Generic messages also force users to guess which constraint was violated, producing support tickets that cost real money.

## Severity rationale

Info because generic error messages degrade UX and violate WCAG 2.2 SC 3.3.1 and 3.3.3 but do not directly expose data or enable exploitation.

## Remediation

Define explicit, constraint-naming error strings for every financial validation rule in `src/lib/validationErrors.ts` or inline in the Zod schema.

```ts
// src/lib/schemas.ts
export const transferSchema = z.object({
  amountCents: z.number()
    .int('Amount must be a whole number of cents')
    .min(1, 'Minimum transaction is $0.01')
    .max(99999, 'Maximum transaction is $999.99'),
  routingNumber: z.string()
    .regex(/^\d{9}$/, 'Routing number must be exactly 9 digits')
    .refine(isValidABARoutingNumber, 'Invalid routing number — checksum failed'),
});
```

Return the Zod `issues[0].message` string directly in the API error response so the client can display it verbatim without mapping.

## Detection

- **ID:** `error-clarity`
- **Severity:** `info`
- **What to look for:** List all financial form validation error messages in the codebase. For each, classify whether the message specifies the exact requirement (includes a number, format, or specific constraint) or is generic (fewer than 5 descriptive words). Quote the actual error message string found. Report: "X of Y error messages specify the exact requirement."
- **Pass criteria:** At least 100% of financial validation error messages include the specific constraint (e.g., "Amount must be between $0.01 and $9,999.99", "Routing number must be 9 digits"). No more than 0 messages use generic text like "Invalid input" or "Validation failed".
- **Fail criteria:** Any financial validation error message is generic or does not state the specific requirement.
- **Must not pass when:** Error messages include the field name but not the constraint (e.g., "Invalid amount" without specifying what makes it invalid).
- **Skip (N/A) when:** The project has no financial form validation (0 financial validation error messages found).
- **Detail on fail:** Example: `"Amount validation fails with generic 'Invalid input' instead of 'Amount must be at least $0.01'"`
- **Cross-reference:** The Error Resilience audit covers broader error messaging patterns and user-facing error recovery UX.
- **Remediation:** Use clear, specific error messages in `src/lib/schemas.ts` or validation constants:

  **In `src/lib/validationErrors.ts`:**
  ```ts
  const validationErrors = {
    amountTooLow: 'Minimum transaction is $0.01',
    amountTooHigh: 'Maximum transaction is $9,999.99',
    invalidIBAN: 'Invalid IBAN format',
    invalidRoutingNumber: 'Invalid routing number',
    negativeAmount: 'Amount cannot be negative',
  };

  if (amountCents < 1) {
    return errorResponse(validationErrors.amountTooLow);
  }
  ```

## External references

- wcag 3.3.1
- wcag 3.3.3

Taxons: user-experience

HTML version: https://auditbuffet.com/patterns/ab-001455
