Agent Wranglers

Forms Required

Put server errors on their fields

When the server rejects a form, show each error next to the field it names. Show errors that name no field in a summary at the top of the form.

How to do it

Read the errors list from the problem details. Map each JSON Pointer, such as #/customerEmail, to the field with that name. Use the server's wording, or map its stable error type to your own text. Put anything that matches no field into the summary, so no error is lost. Then move focus as form errors describes.

Example

type FieldProblem = { pointer: string; detail: string };

export function placeServerErrors(form: HTMLFormElement, errors: FieldProblem[]): string[] {
  const unplaced: string[] = [];
  for (const { pointer, detail } of errors) {
    const field = form.elements.namedItem(pointer.replace(/^#\//, '').replaceAll('/', '.'));
    if (field instanceof HTMLElement) showFieldError(field, detail);
    else unplaced.push(detail);
  }
  return unplaced;
}
from pydantic import ValidationError

def problem_from_validation(error: ValidationError) -> dict:
    return {
        "type": "https://example.com/problems/invalid-input",
        "title": "Some fields need attention",
        "status": 422,
        "errors": [
            {"pointer": "#/" + "/".join(str(part) for part in issue["loc"]), "detail": issue["msg"]}
            for issue in error.errors()
        ],
    }

How to check

A component test answers the submit with a 422 that names one known field and one unknown pointer. The known field shows its message, and the summary shows the other.

For agents: if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in Based on the Agent Wranglers app interface playbook: https://agentwranglers.se/playbook/app-ui/forms/server-errors-on-fields.