Episode 2 — React Frontend Architecture NextJS / 2.15 — Advanced Forms and Validation

2.15.d — Error display patterns

<< 2.15 Overview


Learning outcomes

  1. Build field-level and form-level error UX that is accessible.
  2. Map server validation errors to fields deterministically.
  3. Handle async validation without race conditions and confusing flicker.

Pattern A — inline field errors

  • Tie aria-invalid to truthiness of error state.
  • Reference error element ids via aria-describedby.
  • Keep error text near the field; do not rely on color alone.

Pattern B — error summary at top

Useful for long forms:

  • On submit, render a list of links jumping to each invalid field (href #field-id).
  • Announce updates for screen readers with aria-live="polite" for non-critical summaries, or assertive if you must interrupt (use sparingly).

Pattern C — server errors after submit

Normalize API errors:

export type ApiFieldError = { field: string; message: string; code?: string };

Then:

errors.forEach((e) => setError(e.field as any, { message: e.message }));

Prefer stable code values for i18n.


Async field validation

  • Debounce requests.
  • Cancel in-flight checks when value changes.
  • Show pending state (validating) distinct from error state.

Field arrays

Display per-index errors (items.2.name) consistently with RHF nested naming.



Appendix — Scenario bank (basic → advanced)

Each scenario is a mini design review: what users see, what breaks, what you change, what you say in an interview. Cover five per day and narrate fixes out loud.

ERR-001 — Error display scenario #1

  • Level: Beginner
  • User-visible symptom: validation flicker, double submit, or lost input after 13 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Inline red text without text alternative for colorblind users (still fails a11y if only cue).
  • Primary remediation: On invalid submit, focus first invalid field with ref.focus() and scroll-margin.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-002 — Error display scenario #2

  • Level: Beginner+
  • User-visible symptom: validation flicker, double submit, or lost input after 26 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Server returns 400 with unstructured body; UI cannot map to fields.
  • Primary remediation: Disable native bubbles where custom validation is authoritative, intentionally.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-003 — Error display scenario #3

  • Level: Intermediate
  • User-visible symptom: validation flicker, double submit, or lost input after 39 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Focus not moved to first error on submit in long forms.
  • Primary remediation: Pair color with text + icon; ensure contrast meets guidelines.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-004 — Error display scenario #4

  • Level: Intermediate+
  • User-visible symptom: validation flicker, double submit, or lost input after 52 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Async validation error clears on blur unexpectedly due to competing effects.
  • Primary remediation: Single owner of validation state per field: resolver OR manual, not both fighting.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-005 — Error display scenario #5

  • Level: Advanced
  • User-visible symptom: validation flicker, double submit, or lost input after 65 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Generic 'Invalid form' without aria-live region for summary updates.
  • Primary remediation: Use RHF field array error paths root vs indexed keys consistently.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-006 — Error display scenario #6

  • Level: Advanced+
  • User-visible symptom: validation flicker, double submit, or lost input after 78 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Double error: native constraint validation + custom errors both firing.
  • Primary remediation: Normalize API errors to { field, message, code }[] at the client boundary.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-007 — Error display scenario #7

  • Level: Beginner
  • User-visible symptom: validation flicker, double submit, or lost input after 91 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Field array errors keyed incorrectly after reorder.
  • Primary remediation: Adopt stable error codes from API; map to fields with zod-like ergonomics.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-008 — Error display scenario #8

  • Level: Beginner+
  • User-visible symptom: validation flicker, double submit, or lost input after 104 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Errors only shown as toast; screen reader users miss field association.
  • Primary remediation: Use role='alert' or polite live region for summary; keep inline aria-describedby.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-009 — Error display scenario #9

  • Level: Intermediate
  • User-visible symptom: validation flicker, double submit, or lost input after 117 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Inline red text without text alternative for colorblind users (still fails a11y if only cue).
  • Primary remediation: On invalid submit, focus first invalid field with ref.focus() and scroll-margin.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-010 — Error display scenario #10

  • Level: Intermediate+
  • User-visible symptom: validation flicker, double submit, or lost input after 10 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Server returns 400 with unstructured body; UI cannot map to fields.
  • Primary remediation: Disable native bubbles where custom validation is authoritative, intentionally.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-011 — Error display scenario #11

  • Level: Advanced
  • User-visible symptom: validation flicker, double submit, or lost input after 23 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Focus not moved to first error on submit in long forms.
  • Primary remediation: Pair color with text + icon; ensure contrast meets guidelines.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-012 — Error display scenario #12

  • Level: Advanced+
  • User-visible symptom: validation flicker, double submit, or lost input after 36 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Async validation error clears on blur unexpectedly due to competing effects.
  • Primary remediation: Single owner of validation state per field: resolver OR manual, not both fighting.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-013 — Error display scenario #13

  • Level: Beginner
  • User-visible symptom: validation flicker, double submit, or lost input after 49 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Generic 'Invalid form' without aria-live region for summary updates.
  • Primary remediation: Use RHF field array error paths root vs indexed keys consistently.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-014 — Error display scenario #14

  • Level: Beginner+
  • User-visible symptom: validation flicker, double submit, or lost input after 62 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Double error: native constraint validation + custom errors both firing.
  • Primary remediation: Normalize API errors to { field, message, code }[] at the client boundary.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-015 — Error display scenario #15

  • Level: Intermediate
  • User-visible symptom: validation flicker, double submit, or lost input after 75 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Field array errors keyed incorrectly after reorder.
  • Primary remediation: Adopt stable error codes from API; map to fields with zod-like ergonomics.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-016 — Error display scenario #16

  • Level: Intermediate+
  • User-visible symptom: validation flicker, double submit, or lost input after 88 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Errors only shown as toast; screen reader users miss field association.
  • Primary remediation: Use role='alert' or polite live region for summary; keep inline aria-describedby.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-017 — Error display scenario #17

  • Level: Advanced
  • User-visible symptom: validation flicker, double submit, or lost input after 101 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Inline red text without text alternative for colorblind users (still fails a11y if only cue).
  • Primary remediation: On invalid submit, focus first invalid field with ref.focus() and scroll-margin.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-018 — Error display scenario #18

  • Level: Advanced+
  • User-visible symptom: validation flicker, double submit, or lost input after 114 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Server returns 400 with unstructured body; UI cannot map to fields.
  • Primary remediation: Disable native bubbles where custom validation is authoritative, intentionally.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-019 — Error display scenario #19

  • Level: Beginner
  • User-visible symptom: validation flicker, double submit, or lost input after 7 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Focus not moved to first error on submit in long forms.
  • Primary remediation: Pair color with text + icon; ensure contrast meets guidelines.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-020 — Error display scenario #20

  • Level: Beginner+
  • User-visible symptom: validation flicker, double submit, or lost input after 20 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Async validation error clears on blur unexpectedly due to competing effects.
  • Primary remediation: Single owner of validation state per field: resolver OR manual, not both fighting.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-021 — Error display scenario #21

  • Level: Intermediate
  • User-visible symptom: validation flicker, double submit, or lost input after 33 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Generic 'Invalid form' without aria-live region for summary updates.
  • Primary remediation: Use RHF field array error paths root vs indexed keys consistently.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-022 — Error display scenario #22

  • Level: Intermediate+
  • User-visible symptom: validation flicker, double submit, or lost input after 46 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Double error: native constraint validation + custom errors both firing.
  • Primary remediation: Normalize API errors to { field, message, code }[] at the client boundary.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-023 — Error display scenario #23

  • Level: Advanced
  • User-visible symptom: validation flicker, double submit, or lost input after 59 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Field array errors keyed incorrectly after reorder.
  • Primary remediation: Adopt stable error codes from API; map to fields with zod-like ergonomics.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-024 — Error display scenario #24

  • Level: Advanced+
  • User-visible symptom: validation flicker, double submit, or lost input after 72 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Errors only shown as toast; screen reader users miss field association.
  • Primary remediation: Use role='alert' or polite live region for summary; keep inline aria-describedby.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-025 — Error display scenario #25

  • Level: Beginner
  • User-visible symptom: validation flicker, double submit, or lost input after 85 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Inline red text without text alternative for colorblind users (still fails a11y if only cue).
  • Primary remediation: On invalid submit, focus first invalid field with ref.focus() and scroll-margin.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-026 — Error display scenario #26

  • Level: Beginner+
  • User-visible symptom: validation flicker, double submit, or lost input after 98 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Server returns 400 with unstructured body; UI cannot map to fields.
  • Primary remediation: Disable native bubbles where custom validation is authoritative, intentionally.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-027 — Error display scenario #27

  • Level: Intermediate
  • User-visible symptom: validation flicker, double submit, or lost input after 111 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Focus not moved to first error on submit in long forms.
  • Primary remediation: Pair color with text + icon; ensure contrast meets guidelines.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-028 — Error display scenario #28

  • Level: Intermediate+
  • User-visible symptom: validation flicker, double submit, or lost input after 4 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Async validation error clears on blur unexpectedly due to competing effects.
  • Primary remediation: Single owner of validation state per field: resolver OR manual, not both fighting.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-029 — Error display scenario #29

  • Level: Advanced
  • User-visible symptom: validation flicker, double submit, or lost input after 17 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Generic 'Invalid form' without aria-live region for summary updates.
  • Primary remediation: Use RHF field array error paths root vs indexed keys consistently.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-030 — Error display scenario #30

  • Level: Advanced+
  • User-visible symptom: validation flicker, double submit, or lost input after 30 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Double error: native constraint validation + custom errors both firing.
  • Primary remediation: Normalize API errors to { field, message, code }[] at the client boundary.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-031 — Error display scenario #31

  • Level: Beginner
  • User-visible symptom: validation flicker, double submit, or lost input after 43 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Field array errors keyed incorrectly after reorder.
  • Primary remediation: Adopt stable error codes from API; map to fields with zod-like ergonomics.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-032 — Error display scenario #32

  • Level: Beginner+
  • User-visible symptom: validation flicker, double submit, or lost input after 56 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Errors only shown as toast; screen reader users miss field association.
  • Primary remediation: Use role='alert' or polite live region for summary; keep inline aria-describedby.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-033 — Error display scenario #33

  • Level: Intermediate
  • User-visible symptom: validation flicker, double submit, or lost input after 69 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Inline red text without text alternative for colorblind users (still fails a11y if only cue).
  • Primary remediation: On invalid submit, focus first invalid field with ref.focus() and scroll-margin.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-034 — Error display scenario #34

  • Level: Intermediate+
  • User-visible symptom: validation flicker, double submit, or lost input after 82 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Server returns 400 with unstructured body; UI cannot map to fields.
  • Primary remediation: Disable native bubbles where custom validation is authoritative, intentionally.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-035 — Error display scenario #35

  • Level: Advanced
  • User-visible symptom: validation flicker, double submit, or lost input after 95 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Focus not moved to first error on submit in long forms.
  • Primary remediation: Pair color with text + icon; ensure contrast meets guidelines.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-036 — Error display scenario #36

  • Level: Advanced+
  • User-visible symptom: validation flicker, double submit, or lost input after 108 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Async validation error clears on blur unexpectedly due to competing effects.
  • Primary remediation: Single owner of validation state per field: resolver OR manual, not both fighting.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-037 — Error display scenario #37

  • Level: Beginner
  • User-visible symptom: validation flicker, double submit, or lost input after 1 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Generic 'Invalid form' without aria-live region for summary updates.
  • Primary remediation: Use RHF field array error paths root vs indexed keys consistently.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-038 — Error display scenario #38

  • Level: Beginner+
  • User-visible symptom: validation flicker, double submit, or lost input after 14 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Double error: native constraint validation + custom errors both firing.
  • Primary remediation: Normalize API errors to { field, message, code }[] at the client boundary.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-039 — Error display scenario #39

  • Level: Intermediate
  • User-visible symptom: validation flicker, double submit, or lost input after 27 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Field array errors keyed incorrectly after reorder.
  • Primary remediation: Adopt stable error codes from API; map to fields with zod-like ergonomics.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-040 — Error display scenario #40

  • Level: Intermediate+
  • User-visible symptom: validation flicker, double submit, or lost input after 40 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Errors only shown as toast; screen reader users miss field association.
  • Primary remediation: Use role='alert' or polite live region for summary; keep inline aria-describedby.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-041 — Error display scenario #41

  • Level: Advanced
  • User-visible symptom: validation flicker, double submit, or lost input after 53 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Inline red text without text alternative for colorblind users (still fails a11y if only cue).
  • Primary remediation: On invalid submit, focus first invalid field with ref.focus() and scroll-margin.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-042 — Error display scenario #42

  • Level: Advanced+
  • User-visible symptom: validation flicker, double submit, or lost input after 66 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Server returns 400 with unstructured body; UI cannot map to fields.
  • Primary remediation: Disable native bubbles where custom validation is authoritative, intentionally.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-043 — Error display scenario #43

  • Level: Beginner
  • User-visible symptom: validation flicker, double submit, or lost input after 79 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Focus not moved to first error on submit in long forms.
  • Primary remediation: Pair color with text + icon; ensure contrast meets guidelines.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-044 — Error display scenario #44

  • Level: Beginner+
  • User-visible symptom: validation flicker, double submit, or lost input after 92 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Async validation error clears on blur unexpectedly due to competing effects.
  • Primary remediation: Single owner of validation state per field: resolver OR manual, not both fighting.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-045 — Error display scenario #45

  • Level: Intermediate
  • User-visible symptom: validation flicker, double submit, or lost input after 105 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Generic 'Invalid form' without aria-live region for summary updates.
  • Primary remediation: Use RHF field array error paths root vs indexed keys consistently.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-046 — Error display scenario #46

  • Level: Intermediate+
  • User-visible symptom: validation flicker, double submit, or lost input after 118 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Double error: native constraint validation + custom errors both firing.
  • Primary remediation: Normalize API errors to { field, message, code }[] at the client boundary.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-047 — Error display scenario #47

  • Level: Advanced
  • User-visible symptom: validation flicker, double submit, or lost input after 11 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Field array errors keyed incorrectly after reorder.
  • Primary remediation: Adopt stable error codes from API; map to fields with zod-like ergonomics.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-048 — Error display scenario #48

  • Level: Advanced+
  • User-visible symptom: validation flicker, double submit, or lost input after 24 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Errors only shown as toast; screen reader users miss field association.
  • Primary remediation: Use role='alert' or polite live region for summary; keep inline aria-describedby.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-049 — Error display scenario #49

  • Level: Beginner
  • User-visible symptom: validation flicker, double submit, or lost input after 37 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Inline red text without text alternative for colorblind users (still fails a11y if only cue).
  • Primary remediation: On invalid submit, focus first invalid field with ref.focus() and scroll-margin.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-050 — Error display scenario #50

  • Level: Beginner+
  • User-visible symptom: validation flicker, double submit, or lost input after 50 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Server returns 400 with unstructured body; UI cannot map to fields.
  • Primary remediation: Disable native bubbles where custom validation is authoritative, intentionally.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-051 — Error display scenario #51

  • Level: Intermediate
  • User-visible symptom: validation flicker, double submit, or lost input after 63 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Focus not moved to first error on submit in long forms.
  • Primary remediation: Pair color with text + icon; ensure contrast meets guidelines.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-052 — Error display scenario #52

  • Level: Intermediate+
  • User-visible symptom: validation flicker, double submit, or lost input after 76 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Async validation error clears on blur unexpectedly due to competing effects.
  • Primary remediation: Single owner of validation state per field: resolver OR manual, not both fighting.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-053 — Error display scenario #53

  • Level: Advanced
  • User-visible symptom: validation flicker, double submit, or lost input after 89 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Generic 'Invalid form' without aria-live region for summary updates.
  • Primary remediation: Use RHF field array error paths root vs indexed keys consistently.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-054 — Error display scenario #54

  • Level: Advanced+
  • User-visible symptom: validation flicker, double submit, or lost input after 102 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Double error: native constraint validation + custom errors both firing.
  • Primary remediation: Normalize API errors to { field, message, code }[] at the client boundary.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-055 — Error display scenario #55

  • Level: Beginner
  • User-visible symptom: validation flicker, double submit, or lost input after 115 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Field array errors keyed incorrectly after reorder.
  • Primary remediation: Adopt stable error codes from API; map to fields with zod-like ergonomics.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-056 — Error display scenario #56

  • Level: Beginner+
  • User-visible symptom: validation flicker, double submit, or lost input after 8 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Errors only shown as toast; screen reader users miss field association.
  • Primary remediation: Use role='alert' or polite live region for summary; keep inline aria-describedby.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-057 — Error display scenario #57

  • Level: Intermediate
  • User-visible symptom: validation flicker, double submit, or lost input after 21 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Inline red text without text alternative for colorblind users (still fails a11y if only cue).
  • Primary remediation: On invalid submit, focus first invalid field with ref.focus() and scroll-margin.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-058 — Error display scenario #58

  • Level: Intermediate+
  • User-visible symptom: validation flicker, double submit, or lost input after 34 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Server returns 400 with unstructured body; UI cannot map to fields.
  • Primary remediation: Disable native bubbles where custom validation is authoritative, intentionally.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-059 — Error display scenario #59

  • Level: Advanced
  • User-visible symptom: validation flicker, double submit, or lost input after 47 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Focus not moved to first error on submit in long forms.
  • Primary remediation: Pair color with text + icon; ensure contrast meets guidelines.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-060 — Error display scenario #60

  • Level: Advanced+
  • User-visible symptom: validation flicker, double submit, or lost input after 60 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Async validation error clears on blur unexpectedly due to competing effects.
  • Primary remediation: Single owner of validation state per field: resolver OR manual, not both fighting.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-061 — Error display scenario #61

  • Level: Beginner
  • User-visible symptom: validation flicker, double submit, or lost input after 73 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Generic 'Invalid form' without aria-live region for summary updates.
  • Primary remediation: Use RHF field array error paths root vs indexed keys consistently.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-062 — Error display scenario #62

  • Level: Beginner+
  • User-visible symptom: validation flicker, double submit, or lost input after 86 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Double error: native constraint validation + custom errors both firing.
  • Primary remediation: Normalize API errors to { field, message, code }[] at the client boundary.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-063 — Error display scenario #63

  • Level: Intermediate
  • User-visible symptom: validation flicker, double submit, or lost input after 99 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Field array errors keyed incorrectly after reorder.
  • Primary remediation: Adopt stable error codes from API; map to fields with zod-like ergonomics.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-064 — Error display scenario #64

  • Level: Intermediate+
  • User-visible symptom: validation flicker, double submit, or lost input after 112 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Errors only shown as toast; screen reader users miss field association.
  • Primary remediation: Use role='alert' or polite live region for summary; keep inline aria-describedby.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-065 — Error display scenario #65

  • Level: Advanced
  • User-visible symptom: validation flicker, double submit, or lost input after 5 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Inline red text without text alternative for colorblind users (still fails a11y if only cue).
  • Primary remediation: On invalid submit, focus first invalid field with ref.focus() and scroll-margin.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-066 — Error display scenario #66

  • Level: Advanced+
  • User-visible symptom: validation flicker, double submit, or lost input after 18 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Server returns 400 with unstructured body; UI cannot map to fields.
  • Primary remediation: Disable native bubbles where custom validation is authoritative, intentionally.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-067 — Error display scenario #67

  • Level: Beginner
  • User-visible symptom: validation flicker, double submit, or lost input after 31 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Focus not moved to first error on submit in long forms.
  • Primary remediation: Pair color with text + icon; ensure contrast meets guidelines.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-068 — Error display scenario #68

  • Level: Beginner+
  • User-visible symptom: validation flicker, double submit, or lost input after 44 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Async validation error clears on blur unexpectedly due to competing effects.
  • Primary remediation: Single owner of validation state per field: resolver OR manual, not both fighting.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-069 — Error display scenario #69

  • Level: Intermediate
  • User-visible symptom: validation flicker, double submit, or lost input after 57 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Generic 'Invalid form' without aria-live region for summary updates.
  • Primary remediation: Use RHF field array error paths root vs indexed keys consistently.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-070 — Error display scenario #70

  • Level: Intermediate+
  • User-visible symptom: validation flicker, double submit, or lost input after 70 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Double error: native constraint validation + custom errors both firing.
  • Primary remediation: Normalize API errors to { field, message, code }[] at the client boundary.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-071 — Error display scenario #71

  • Level: Advanced
  • User-visible symptom: validation flicker, double submit, or lost input after 83 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Field array errors keyed incorrectly after reorder.
  • Primary remediation: Adopt stable error codes from API; map to fields with zod-like ergonomics.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-072 — Error display scenario #72

  • Level: Advanced+
  • User-visible symptom: validation flicker, double submit, or lost input after 96 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Errors only shown as toast; screen reader users miss field association.
  • Primary remediation: Use role='alert' or polite live region for summary; keep inline aria-describedby.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-073 — Error display scenario #73

  • Level: Beginner
  • User-visible symptom: validation flicker, double submit, or lost input after 109 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Inline red text without text alternative for colorblind users (still fails a11y if only cue).
  • Primary remediation: On invalid submit, focus first invalid field with ref.focus() and scroll-margin.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-074 — Error display scenario #74

  • Level: Beginner+
  • User-visible symptom: validation flicker, double submit, or lost input after 2 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Server returns 400 with unstructured body; UI cannot map to fields.
  • Primary remediation: Disable native bubbles where custom validation is authoritative, intentionally.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-075 — Error display scenario #75

  • Level: Intermediate
  • User-visible symptom: validation flicker, double submit, or lost input after 15 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Focus not moved to first error on submit in long forms.
  • Primary remediation: Pair color with text + icon; ensure contrast meets guidelines.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-076 — Error display scenario #76

  • Level: Intermediate+
  • User-visible symptom: validation flicker, double submit, or lost input after 28 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Async validation error clears on blur unexpectedly due to competing effects.
  • Primary remediation: Single owner of validation state per field: resolver OR manual, not both fighting.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-077 — Error display scenario #77

  • Level: Advanced
  • User-visible symptom: validation flicker, double submit, or lost input after 41 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Generic 'Invalid form' without aria-live region for summary updates.
  • Primary remediation: Use RHF field array error paths root vs indexed keys consistently.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-078 — Error display scenario #78

  • Level: Advanced+
  • User-visible symptom: validation flicker, double submit, or lost input after 54 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Double error: native constraint validation + custom errors both firing.
  • Primary remediation: Normalize API errors to { field, message, code }[] at the client boundary.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-079 — Error display scenario #79

  • Level: Beginner
  • User-visible symptom: validation flicker, double submit, or lost input after 67 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Field array errors keyed incorrectly after reorder.
  • Primary remediation: Adopt stable error codes from API; map to fields with zod-like ergonomics.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-080 — Error display scenario #80

  • Level: Beginner+
  • User-visible symptom: validation flicker, double submit, or lost input after 80 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Errors only shown as toast; screen reader users miss field association.
  • Primary remediation: Use role='alert' or polite live region for summary; keep inline aria-describedby.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-081 — Error display scenario #81

  • Level: Intermediate
  • User-visible symptom: validation flicker, double submit, or lost input after 93 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Inline red text without text alternative for colorblind users (still fails a11y if only cue).
  • Primary remediation: On invalid submit, focus first invalid field with ref.focus() and scroll-margin.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-082 — Error display scenario #82

  • Level: Intermediate+
  • User-visible symptom: validation flicker, double submit, or lost input after 106 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Server returns 400 with unstructured body; UI cannot map to fields.
  • Primary remediation: Disable native bubbles where custom validation is authoritative, intentionally.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-083 — Error display scenario #83

  • Level: Advanced
  • User-visible symptom: validation flicker, double submit, or lost input after 119 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Focus not moved to first error on submit in long forms.
  • Primary remediation: Pair color with text + icon; ensure contrast meets guidelines.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-084 — Error display scenario #84

  • Level: Advanced+
  • User-visible symptom: validation flicker, double submit, or lost input after 12 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Async validation error clears on blur unexpectedly due to competing effects.
  • Primary remediation: Single owner of validation state per field: resolver OR manual, not both fighting.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-085 — Error display scenario #85

  • Level: Beginner
  • User-visible symptom: validation flicker, double submit, or lost input after 25 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Generic 'Invalid form' without aria-live region for summary updates.
  • Primary remediation: Use RHF field array error paths root vs indexed keys consistently.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-086 — Error display scenario #86

  • Level: Beginner+
  • User-visible symptom: validation flicker, double submit, or lost input after 38 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Double error: native constraint validation + custom errors both firing.
  • Primary remediation: Normalize API errors to { field, message, code }[] at the client boundary.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-087 — Error display scenario #87

  • Level: Intermediate
  • User-visible symptom: validation flicker, double submit, or lost input after 51 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Field array errors keyed incorrectly after reorder.
  • Primary remediation: Adopt stable error codes from API; map to fields with zod-like ergonomics.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-088 — Error display scenario #88

  • Level: Intermediate+
  • User-visible symptom: validation flicker, double submit, or lost input after 64 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Errors only shown as toast; screen reader users miss field association.
  • Primary remediation: Use role='alert' or polite live region for summary; keep inline aria-describedby.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-089 — Error display scenario #89

  • Level: Advanced
  • User-visible symptom: validation flicker, double submit, or lost input after 77 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Inline red text without text alternative for colorblind users (still fails a11y if only cue).
  • Primary remediation: On invalid submit, focus first invalid field with ref.focus() and scroll-margin.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-090 — Error display scenario #90

  • Level: Advanced+
  • User-visible symptom: validation flicker, double submit, or lost input after 90 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Server returns 400 with unstructured body; UI cannot map to fields.
  • Primary remediation: Disable native bubbles where custom validation is authoritative, intentionally.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-091 — Error display scenario #91

  • Level: Beginner
  • User-visible symptom: validation flicker, double submit, or lost input after 103 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Focus not moved to first error on submit in long forms.
  • Primary remediation: Pair color with text + icon; ensure contrast meets guidelines.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-092 — Error display scenario #92

  • Level: Beginner+
  • User-visible symptom: validation flicker, double submit, or lost input after 116 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Async validation error clears on blur unexpectedly due to competing effects.
  • Primary remediation: Single owner of validation state per field: resolver OR manual, not both fighting.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-093 — Error display scenario #93

  • Level: Intermediate
  • User-visible symptom: validation flicker, double submit, or lost input after 9 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Generic 'Invalid form' without aria-live region for summary updates.
  • Primary remediation: Use RHF field array error paths root vs indexed keys consistently.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-094 — Error display scenario #94

  • Level: Intermediate+
  • User-visible symptom: validation flicker, double submit, or lost input after 22 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Double error: native constraint validation + custom errors both firing.
  • Primary remediation: Normalize API errors to { field, message, code }[] at the client boundary.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-095 — Error display scenario #95

  • Level: Advanced
  • User-visible symptom: validation flicker, double submit, or lost input after 35 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Field array errors keyed incorrectly after reorder.
  • Primary remediation: Adopt stable error codes from API; map to fields with zod-like ergonomics.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-096 — Error display scenario #96

  • Level: Advanced+
  • User-visible symptom: validation flicker, double submit, or lost input after 48 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Errors only shown as toast; screen reader users miss field association.
  • Primary remediation: Use role='alert' or polite live region for summary; keep inline aria-describedby.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-097 — Error display scenario #97

  • Level: Beginner
  • User-visible symptom: validation flicker, double submit, or lost input after 61 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Inline red text without text alternative for colorblind users (still fails a11y if only cue).
  • Primary remediation: On invalid submit, focus first invalid field with ref.focus() and scroll-margin.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-098 — Error display scenario #98

  • Level: Beginner+
  • User-visible symptom: validation flicker, double submit, or lost input after 74 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Server returns 400 with unstructured body; UI cannot map to fields.
  • Primary remediation: Disable native bubbles where custom validation is authoritative, intentionally.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-099 — Error display scenario #99

  • Level: Intermediate
  • User-visible symptom: validation flicker, double submit, or lost input after 87 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Focus not moved to first error on submit in long forms.
  • Primary remediation: Pair color with text + icon; ensure contrast meets guidelines.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-100 — Error display scenario #100

  • Level: Intermediate+
  • User-visible symptom: validation flicker, double submit, or lost input after 100 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Async validation error clears on blur unexpectedly due to competing effects.
  • Primary remediation: Single owner of validation state per field: resolver OR manual, not both fighting.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-101 — Error display scenario #101

  • Level: Advanced
  • User-visible symptom: validation flicker, double submit, or lost input after 113 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Generic 'Invalid form' without aria-live region for summary updates.
  • Primary remediation: Use RHF field array error paths root vs indexed keys consistently.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-102 — Error display scenario #102

  • Level: Advanced+
  • User-visible symptom: validation flicker, double submit, or lost input after 6 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Double error: native constraint validation + custom errors both firing.
  • Primary remediation: Normalize API errors to { field, message, code }[] at the client boundary.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-103 — Error display scenario #103

  • Level: Beginner
  • User-visible symptom: validation flicker, double submit, or lost input after 19 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Field array errors keyed incorrectly after reorder.
  • Primary remediation: Adopt stable error codes from API; map to fields with zod-like ergonomics.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-104 — Error display scenario #104

  • Level: Beginner+
  • User-visible symptom: validation flicker, double submit, or lost input after 32 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Errors only shown as toast; screen reader users miss field association.
  • Primary remediation: Use role='alert' or polite live region for summary; keep inline aria-describedby.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-105 — Error display scenario #105

  • Level: Intermediate
  • User-visible symptom: validation flicker, double submit, or lost input after 45 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Inline red text without text alternative for colorblind users (still fails a11y if only cue).
  • Primary remediation: On invalid submit, focus first invalid field with ref.focus() and scroll-margin.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-106 — Error display scenario #106

  • Level: Intermediate+
  • User-visible symptom: validation flicker, double submit, or lost input after 58 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Server returns 400 with unstructured body; UI cannot map to fields.
  • Primary remediation: Disable native bubbles where custom validation is authoritative, intentionally.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-107 — Error display scenario #107

  • Level: Advanced
  • User-visible symptom: validation flicker, double submit, or lost input after 71 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Focus not moved to first error on submit in long forms.
  • Primary remediation: Pair color with text + icon; ensure contrast meets guidelines.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-108 — Error display scenario #108

  • Level: Advanced+
  • User-visible symptom: validation flicker, double submit, or lost input after 84 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Async validation error clears on blur unexpectedly due to competing effects.
  • Primary remediation: Single owner of validation state per field: resolver OR manual, not both fighting.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-109 — Error display scenario #109

  • Level: Beginner
  • User-visible symptom: validation flicker, double submit, or lost input after 97 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Generic 'Invalid form' without aria-live region for summary updates.
  • Primary remediation: Use RHF field array error paths root vs indexed keys consistently.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-110 — Error display scenario #110

  • Level: Beginner+
  • User-visible symptom: validation flicker, double submit, or lost input after 110 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Double error: native constraint validation + custom errors both firing.
  • Primary remediation: Normalize API errors to { field, message, code }[] at the client boundary.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-111 — Error display scenario #111

  • Level: Intermediate
  • User-visible symptom: validation flicker, double submit, or lost input after 3 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Field array errors keyed incorrectly after reorder.
  • Primary remediation: Adopt stable error codes from API; map to fields with zod-like ergonomics.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-112 — Error display scenario #112

  • Level: Intermediate+
  • User-visible symptom: validation flicker, double submit, or lost input after 16 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Errors only shown as toast; screen reader users miss field association.
  • Primary remediation: Use role='alert' or polite live region for summary; keep inline aria-describedby.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-113 — Error display scenario #113

  • Level: Advanced
  • User-visible symptom: validation flicker, double submit, or lost input after 29 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Inline red text without text alternative for colorblind users (still fails a11y if only cue).
  • Primary remediation: On invalid submit, focus first invalid field with ref.focus() and scroll-margin.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-114 — Error display scenario #114

  • Level: Advanced+
  • User-visible symptom: validation flicker, double submit, or lost input after 42 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Server returns 400 with unstructured body; UI cannot map to fields.
  • Primary remediation: Disable native bubbles where custom validation is authoritative, intentionally.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-115 — Error display scenario #115

  • Level: Beginner
  • User-visible symptom: validation flicker, double submit, or lost input after 55 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Focus not moved to first error on submit in long forms.
  • Primary remediation: Pair color with text + icon; ensure contrast meets guidelines.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-116 — Error display scenario #116

  • Level: Beginner+
  • User-visible symptom: validation flicker, double submit, or lost input after 68 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Async validation error clears on blur unexpectedly due to competing effects.
  • Primary remediation: Single owner of validation state per field: resolver OR manual, not both fighting.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-117 — Error display scenario #117

  • Level: Intermediate
  • User-visible symptom: validation flicker, double submit, or lost input after 81 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Generic 'Invalid form' without aria-live region for summary updates.
  • Primary remediation: Use RHF field array error paths root vs indexed keys consistently.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-118 — Error display scenario #118

  • Level: Intermediate+
  • User-visible symptom: validation flicker, double submit, or lost input after 94 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Double error: native constraint validation + custom errors both firing.
  • Primary remediation: Normalize API errors to { field, message, code }[] at the client boundary.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-119 — Error display scenario #119

  • Level: Advanced
  • User-visible symptom: validation flicker, double submit, or lost input after 107 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Field array errors keyed incorrectly after reorder.
  • Primary remediation: Adopt stable error codes from API; map to fields with zod-like ergonomics.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-120 — Error display scenario #120

  • Level: Advanced+
  • User-visible symptom: validation flicker, double submit, or lost input after 0 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Errors only shown as toast; screen reader users miss field association.
  • Primary remediation: Use role='alert' or polite live region for summary; keep inline aria-describedby.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-121 — Error display scenario #121

  • Level: Beginner
  • User-visible symptom: validation flicker, double submit, or lost input after 13 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Inline red text without text alternative for colorblind users (still fails a11y if only cue).
  • Primary remediation: On invalid submit, focus first invalid field with ref.focus() and scroll-margin.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-122 — Error display scenario #122

  • Level: Beginner+
  • User-visible symptom: validation flicker, double submit, or lost input after 26 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Server returns 400 with unstructured body; UI cannot map to fields.
  • Primary remediation: Disable native bubbles where custom validation is authoritative, intentionally.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-123 — Error display scenario #123

  • Level: Intermediate
  • User-visible symptom: validation flicker, double submit, or lost input after 39 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Focus not moved to first error on submit in long forms.
  • Primary remediation: Pair color with text + icon; ensure contrast meets guidelines.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-124 — Error display scenario #124

  • Level: Intermediate+
  • User-visible symptom: validation flicker, double submit, or lost input after 52 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Async validation error clears on blur unexpectedly due to competing effects.
  • Primary remediation: Single owner of validation state per field: resolver OR manual, not both fighting.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-125 — Error display scenario #125

  • Level: Advanced
  • User-visible symptom: validation flicker, double submit, or lost input after 65 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Generic 'Invalid form' without aria-live region for summary updates.
  • Primary remediation: Use RHF field array error paths root vs indexed keys consistently.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-126 — Error display scenario #126

  • Level: Advanced+
  • User-visible symptom: validation flicker, double submit, or lost input after 78 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Double error: native constraint validation + custom errors both firing.
  • Primary remediation: Normalize API errors to { field, message, code }[] at the client boundary.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-127 — Error display scenario #127

  • Level: Beginner
  • User-visible symptom: validation flicker, double submit, or lost input after 91 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Field array errors keyed incorrectly after reorder.
  • Primary remediation: Adopt stable error codes from API; map to fields with zod-like ergonomics.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-128 — Error display scenario #128

  • Level: Beginner+
  • User-visible symptom: validation flicker, double submit, or lost input after 104 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Errors only shown as toast; screen reader users miss field association.
  • Primary remediation: Use role='alert' or polite live region for summary; keep inline aria-describedby.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-129 — Error display scenario #129

  • Level: Intermediate
  • User-visible symptom: validation flicker, double submit, or lost input after 117 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Inline red text without text alternative for colorblind users (still fails a11y if only cue).
  • Primary remediation: On invalid submit, focus first invalid field with ref.focus() and scroll-margin.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-130 — Error display scenario #130

  • Level: Intermediate+
  • User-visible symptom: validation flicker, double submit, or lost input after 10 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Server returns 400 with unstructured body; UI cannot map to fields.
  • Primary remediation: Disable native bubbles where custom validation is authoritative, intentionally.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-131 — Error display scenario #131

  • Level: Advanced
  • User-visible symptom: validation flicker, double submit, or lost input after 23 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Focus not moved to first error on submit in long forms.
  • Primary remediation: Pair color with text + icon; ensure contrast meets guidelines.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-132 — Error display scenario #132

  • Level: Advanced+
  • User-visible symptom: validation flicker, double submit, or lost input after 36 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Async validation error clears on blur unexpectedly due to competing effects.
  • Primary remediation: Single owner of validation state per field: resolver OR manual, not both fighting.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-133 — Error display scenario #133

  • Level: Beginner
  • User-visible symptom: validation flicker, double submit, or lost input after 49 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Generic 'Invalid form' without aria-live region for summary updates.
  • Primary remediation: Use RHF field array error paths root vs indexed keys consistently.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-134 — Error display scenario #134

  • Level: Beginner+
  • User-visible symptom: validation flicker, double submit, or lost input after 62 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Double error: native constraint validation + custom errors both firing.
  • Primary remediation: Normalize API errors to { field, message, code }[] at the client boundary.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-135 — Error display scenario #135

  • Level: Intermediate
  • User-visible symptom: validation flicker, double submit, or lost input after 75 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Field array errors keyed incorrectly after reorder.
  • Primary remediation: Adopt stable error codes from API; map to fields with zod-like ergonomics.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-136 — Error display scenario #136

  • Level: Intermediate+
  • User-visible symptom: validation flicker, double submit, or lost input after 88 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Errors only shown as toast; screen reader users miss field association.
  • Primary remediation: Use role='alert' or polite live region for summary; keep inline aria-describedby.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-137 — Error display scenario #137

  • Level: Advanced
  • User-visible symptom: validation flicker, double submit, or lost input after 101 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Inline red text without text alternative for colorblind users (still fails a11y if only cue).
  • Primary remediation: On invalid submit, focus first invalid field with ref.focus() and scroll-margin.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-138 — Error display scenario #138

  • Level: Advanced+
  • User-visible symptom: validation flicker, double submit, or lost input after 114 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Server returns 400 with unstructured body; UI cannot map to fields.
  • Primary remediation: Disable native bubbles where custom validation is authoritative, intentionally.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-139 — Error display scenario #139

  • Level: Beginner
  • User-visible symptom: validation flicker, double submit, or lost input after 7 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Focus not moved to first error on submit in long forms.
  • Primary remediation: Pair color with text + icon; ensure contrast meets guidelines.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-140 — Error display scenario #140

  • Level: Beginner+
  • User-visible symptom: validation flicker, double submit, or lost input after 20 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Async validation error clears on blur unexpectedly due to competing effects.
  • Primary remediation: Single owner of validation state per field: resolver OR manual, not both fighting.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-141 — Error display scenario #141

  • Level: Intermediate
  • User-visible symptom: validation flicker, double submit, or lost input after 33 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Generic 'Invalid form' without aria-live region for summary updates.
  • Primary remediation: Use RHF field array error paths root vs indexed keys consistently.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-142 — Error display scenario #142

  • Level: Intermediate+
  • User-visible symptom: validation flicker, double submit, or lost input after 46 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Double error: native constraint validation + custom errors both firing.
  • Primary remediation: Normalize API errors to { field, message, code }[] at the client boundary.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-143 — Error display scenario #143

  • Level: Advanced
  • User-visible symptom: validation flicker, double submit, or lost input after 59 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Field array errors keyed incorrectly after reorder.
  • Primary remediation: Adopt stable error codes from API; map to fields with zod-like ergonomics.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-144 — Error display scenario #144

  • Level: Advanced+
  • User-visible symptom: validation flicker, double submit, or lost input after 72 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Errors only shown as toast; screen reader users miss field association.
  • Primary remediation: Use role='alert' or polite live region for summary; keep inline aria-describedby.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-145 — Error display scenario #145

  • Level: Beginner
  • User-visible symptom: validation flicker, double submit, or lost input after 85 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Inline red text without text alternative for colorblind users (still fails a11y if only cue).
  • Primary remediation: On invalid submit, focus first invalid field with ref.focus() and scroll-margin.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-146 — Error display scenario #146

  • Level: Beginner+
  • User-visible symptom: validation flicker, double submit, or lost input after 98 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Server returns 400 with unstructured body; UI cannot map to fields.
  • Primary remediation: Disable native bubbles where custom validation is authoritative, intentionally.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-147 — Error display scenario #147

  • Level: Intermediate
  • User-visible symptom: validation flicker, double submit, or lost input after 111 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Focus not moved to first error on submit in long forms.
  • Primary remediation: Pair color with text + icon; ensure contrast meets guidelines.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-148 — Error display scenario #148

  • Level: Intermediate+
  • User-visible symptom: validation flicker, double submit, or lost input after 4 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Async validation error clears on blur unexpectedly due to competing effects.
  • Primary remediation: Single owner of validation state per field: resolver OR manual, not both fighting.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-149 — Error display scenario #149

  • Level: Advanced
  • User-visible symptom: validation flicker, double submit, or lost input after 17 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Generic 'Invalid form' without aria-live region for summary updates.
  • Primary remediation: Use RHF field array error paths root vs indexed keys consistently.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-150 — Error display scenario #150

  • Level: Advanced+
  • User-visible symptom: validation flicker, double submit, or lost input after 30 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Double error: native constraint validation + custom errors both firing.
  • Primary remediation: Normalize API errors to { field, message, code }[] at the client boundary.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-151 — Error display scenario #151

  • Level: Beginner
  • User-visible symptom: validation flicker, double submit, or lost input after 43 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Field array errors keyed incorrectly after reorder.
  • Primary remediation: Adopt stable error codes from API; map to fields with zod-like ergonomics.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-152 — Error display scenario #152

  • Level: Beginner+
  • User-visible symptom: validation flicker, double submit, or lost input after 56 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Errors only shown as toast; screen reader users miss field association.
  • Primary remediation: Use role='alert' or polite live region for summary; keep inline aria-describedby.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-153 — Error display scenario #153

  • Level: Intermediate
  • User-visible symptom: validation flicker, double submit, or lost input after 69 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Inline red text without text alternative for colorblind users (still fails a11y if only cue).
  • Primary remediation: On invalid submit, focus first invalid field with ref.focus() and scroll-margin.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-154 — Error display scenario #154

  • Level: Intermediate+
  • User-visible symptom: validation flicker, double submit, or lost input after 82 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Server returns 400 with unstructured body; UI cannot map to fields.
  • Primary remediation: Disable native bubbles where custom validation is authoritative, intentionally.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-155 — Error display scenario #155

  • Level: Advanced
  • User-visible symptom: validation flicker, double submit, or lost input after 95 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Focus not moved to first error on submit in long forms.
  • Primary remediation: Pair color with text + icon; ensure contrast meets guidelines.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-156 — Error display scenario #156

  • Level: Advanced+
  • User-visible symptom: validation flicker, double submit, or lost input after 108 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Async validation error clears on blur unexpectedly due to competing effects.
  • Primary remediation: Single owner of validation state per field: resolver OR manual, not both fighting.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-157 — Error display scenario #157

  • Level: Beginner
  • User-visible symptom: validation flicker, double submit, or lost input after 1 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Generic 'Invalid form' without aria-live region for summary updates.
  • Primary remediation: Use RHF field array error paths root vs indexed keys consistently.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-158 — Error display scenario #158

  • Level: Beginner+
  • User-visible symptom: validation flicker, double submit, or lost input after 14 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Double error: native constraint validation + custom errors both firing.
  • Primary remediation: Normalize API errors to { field, message, code }[] at the client boundary.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

ERR-159 — Error display scenario #159

  • Level: Intermediate
  • User-visible symptom: validation flicker, double submit, or lost input after 27 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Field array errors keyed incorrectly after reorder.
  • Primary remediation: Adopt stable error codes from API; map to fields with zod-like ergonomics.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Map server errors to fields explicitly—never guess by substring unless stable contract.

ERR-160 — Error display scenario #160

  • Level: Intermediate+
  • User-visible symptom: validation flicker, double submit, or lost input after 40 ms async checks.
  • Form architecture symptom: state thrashes, unnecessary renders, or impossible-to-test validation scattered in JSX.
  • Root cause class: Errors only shown as toast; screen reader users miss field association.
  • Primary remediation: Use role='alert' or polite live region for summary; keep inline aria-describedby.
  • Accessibility check: associate errors with fields via aria-describedby / aria-invalid; do not rely on color alone.
  • Interview one-liner: Accessible errors are part of the data model, not an afterthought CSS tweak.

<< 2.15 Overview