A case of missing validation messages

Posted by on March 13, 2025

I’ve recently worked on two very similar issues within the FreeAgent app, which is a Rails web application. The problem that was reported in both cases was that when a user tried to submit invalid data they didn’t get any kind of message indicating what went wrong.

In case it helps someone else (and let’s be honest to remind myself when I undoubtedly come across it again) I thought I’d write down the problem and how I resolved it.

The problem

The symptoms were a form being submitted with invalid content, no update happening and no validation errors appearing. In fact, not much feedback of any kind.

This is the page after triggering an error by submitting a text file for a company’s logo rather than an image:

Screenshot showing a form for a user to select a logo for their company. There are no indications of any problems with the submitted logo.

It doesn’t give much of a clue as to what has happened – if anything!

Heading over to the browser console showed an error message: “Error: Form responses must redirect to another location”

Error message in Chrome developer console reading: "Error: Form responses must redirect to another location"

This is a form using Turbo ( data: { turbo: true } ) and I wasn’t expecting to have to redirect at all. Typically when a create or update action fails we re-render the form to show the error message and that’s exactly what it was doing as per this (simplified) code:

if @logo.save
  redirect_to logo_url(@logo)
else
  render action: :edit
end

But there’s something missing. To figure out what it is, first we need to understand how Turbo interacts with HTTP requests.

When we call render in a controller the default behaviour (the convention in Rails parlance) is for the server to respond with an HTTP response status code of 200 which means “Okay”. Turbo is getting confused because we’ve responded with “Okay” and yet everything is not okay. If it were okay Turbo does expect to get a response in the form of a redirect.

A standard Rails form without Turbo wouldn’t expect this distinction between everything being okay and something being awry and would work fine. Turbo is a bit more picky (and to be honest, rightfully so).

The solution

In the error case, we need to respond with an HTTP response status code that indicates that something’s not quite right. In this case it’s a status code of 422 which means “unprocessable content” or “unprocessable entity”.

Rails helpfully understands symbols for most status codes so we can just do:

render action: :edit, status: :unprocessable_entity

Now, Turbo realises that we’re not on the happy path and re-renders the form including displaying validation error messages.

This is what the page looks like now after submitting an invalid file for a logo:

Screenshot showing a form for a user to select a logo for their company. A red section indicates problems with the submitted logo.

The user now knows both that something went wrong and what the problem was.

The conclusion

The issues were fixed by the addition of a specific HTTP response status code. This indicates to Turbo that the submitted content couldn’t be processed by the server.

It’s a good reminder that the Rails approach of convention over configuration can hide away some of the fundamentals of how web applications work. In this case Turbo is a bit more particular in terms of what responses it expects and we need to accommodate it by being explicit about the response status code.

Disclaimer: I’m no expert with all things Turbo and might not have explained what Turbo does perfectly (any clarifications gratefully received!)