Cross-cutting · Error presentation & API error mapping

The shared plumbing that turns model validation failures and API error payloads into field-level messages and page banners, plus the custom error classes used to signal illegal states and disallowed operations.

AreaCross-cutting
Routes(every form)
Centre modulesalways available
Staff levelsall
Models—
UI labeluser-error / api-error
Coverage4 use cases · 2 happy · 5 failure

Known issues (1)

How it works

Three layers. (1) parseErrors converts an ember-model-validator errors array into a field-keyed object the form components render inline. (2) mapErrors(e, intl.t) translates an API error object, and the better controllers (campaign, proposal, children, play centre) feed it into an errorDetails list. (3) Classification: '4' === adapterError.errors[0].status.charAt() chooses user-error (‘Something is wrong. Please check the following errors:’) for client errors versus api-error (“Something is wrong and it’s not your fault. Please, contact support…”) for server errors — a genuinely good distinction, though it throws if the payload has no string status. The generic fallback is info.default.error.message/info.default.error.title. Custom error classes (NoCookieError, IllegalStateError, NotAllowedError, IllegalArgumentError) are thrown for programming and permission violations; these surface as exceptions, not UI messages. A recurring weakness across the codebase is the bare .catch(() => {}), which hides the reason for a failure — notably on segment refresh, sales-year rejection communications and sales-year enable/disable.

Use cases

Why someone opens this (4)

  • Showing a user exactly which fields are wrong without a page reload.
  • Distinguishing ‘you made a mistake’ from ‘our server failed’ so support tickets land in the right place.
  • Letting the API drive a translated message via errors[0].meta['detail-key'].
  • Guarding developer mistakes with explicit exceptions rather than silent misbehaviour.

Path map

flowchart LR
    F(["Error presentation and API error mapping"]):::feat
    F --> H1["Validation errors shown inline"]:::ok
    F --> H2["API error classified"]:::ok
    F -.-> X1["Error payload without a status"]:::bad
    F -.-> X2["Swallowed failure"]:::bad
    F -.-> X3["Stuck loading flag"]:::bad
    F -.-> X4["Untranslated message"]:::bad
    F -.-> X5["Developer-facing exception"]:::bad
    classDef feat fill:#8c5a3c,stroke:#8c5a3c,color:#ffffff,font-weight:bold
    classDef ok fill:#e3f1ea,stroke:#0d6b42,color:#0d4a2e
    classDef bad fill:#f7e6e2,stroke:#9a2d1c,color:#6e1f13

Happy paths

Validation errors shown inline

  1. User submits an incomplete form.
  2. model.validate() fails and parseErrors keys the messages by field.
  3. nf-error renders each message beside its input and the page scrolls to the top.

API error classified

  1. Save is rejected with a 422.
  2. mapErrors translates each error into errorDetails.
  3. Because the status starts with 4, the user-error banner is shown with the detail list.

Failure paths

QA checklist

Tick these off while regression-testing this feature. The boxes are plain Markdown, so progress is visible in git diffs.

  • ✅ Validation errors shown inline
  • ✅ API error classified
  • ⛔ Error payload without a status
  • ⛔ Swallowed failure
  • ⛔ Stuck loading flag
  • ⛔ Untranslated message
  • ⛔ Developer-facing exception

Implementation


Generated from doc/feature-inventory.json · id xc-error-handling · commit 276788ca6