History, errors, and enhancement

Handle HTTP errors

Show useful server failure or validation markup while keeping the affected controls recoverable.

An HTTP error means the server responded, but the result was not successful. HTMX triggers htmx:responseError, and it does not swap the body by default.

Treat expected validation differently from an unexpected server failure. Submit the task form with an empty title. The server should return 422 with a form fragment designed for display. Allow that deliberately:

document.addEventListener('htmx:beforeSwap', event => {
  const status = event.detail.xhr.status

  if (status === 422) {
    event.detail.shouldSwap = true
    event.detail.isError = false
  }
})

The response body should be the full #new-task form with preserved values and field messages. The server can also send HX-Retarget: #new-task when the original target was #task-list. In DevTools the Network panel shows status 422 and HTML in the response, not JSON.

A 500 should produce a generic message and retry path. Never swap a framework error page or stack trace into the application UI. If the server returns a Rails or Django debug page, the user sees internal details inside your task list. Return a small fragment such as “Something went wrong. Try again.” instead.

Keep the status accurate for monitoring and debugging. Handle 401, 403, 404, 409, 422, and 500 according to their meaning rather than collapsing every problem into 200 OK.

For 403 on delete, return no swap and show “You cannot delete this task.” The row must stay visible. A realistic bug: you use hx-swap="delete" and remove the row on any response. Fix: delete swap runs only on success.

After any error swap, check that controls are still usable. Disabled submit buttons should re-enable. Focus should land somewhere sensible. Validation errors should name the field that failed.

Force each relevant response in development and verify the final DOM, focus, enabled controls, visible message, and Network status. An event firing is not enough if the page is still broken.

Lesson completed