phoenixframework/phoenix

Phoenix.Controller.accepts/2 causes a 500 status code in production.

PsionicAlch opened this issue · 2 comments

Environment

  • Elixir version (elixir -v): 1.17.1
  • Phoenix version (mix deps): 1.7.14
  • Operating system: Linux Ubuntu 22.04 LTS

Actual behavior

Phoenix.Controller.accepts/2 will throw a Phoenix.NotAcceptableError if you add "_format=YOUR_FORMAT" to your URL, where YOUR_FORMAT is not in the list of formats passed to Phoenix.Controller.accepts/2. This is fine during development but during production this will result in a 500 status code to be returned. I tested it on the Phoenix Framework home page as well as another website that I knew was written in Phoenix Framework (https://twomillioncheckboxes.com/)

Screenshot from 2024-07-03 10-30-54
Screenshot from 2024-07-03 10-24-16

Expected behaviour

A 406 Not Acceptable status code (https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/406) should rather be thrown. Another possible behaviour could be to allow the user to specify a default fallback content type so that at the very least there is still something shown on screen.

Screenshot from 2024-07-03 14-42-51
Screenshot from 2024-07-03 14-41-57

Interesting! I have multiple Phoenix apps in production where this works correctly. Do you know how to reproduce this from a new project?

For example:

mix phx.new abcdefg --database sqlite3
cd abcdefg
MIX_ENV=prod mix release
PORT=5001 DATABASE_PATH=./db.sqlite SECRET_KEY_BASE=$(mix phx.gen.secret) PHX_SERVER=true _build/prod/rel/abcdefg/bin/abcdefg start

And visiting http://localhost:5001/?_format=xml correctly renders the Not Acceptable response.

I tried the method you suggested and that resulted in a project with the proper 406 response.

So then I cloned this project, https://github.com/pjullrich/twomillioncheckboxes (it's one of the projects that I knew was live as well as open source). This time I followed the steps suggested on the Phoenix Framework documentation, https://hexdocs.pm/phoenix/deployment.html:

export SECRET_KEY_BASE=$(mix phx.gen.secret)
export DATABASE_URL=ecto://postgres:postgres@localhost/app_dev
mix deps.get --only prod
MIX_ENV=prod mix compile
MIX_ENV=prod mix assets.deploy
PORT=4001 MIX_ENV=prod mix phx.server

I got the project running properly on localhost with a postgresql database running under docker. When I go to localhost:4001 I get the normal website and then when I go to localhost:4001/?_format=json I get the 500 response along with this error message printed in the console:

18:33:03.508 request_id=F97BEEuU1fzJ8MUAAAAF [error] ** (ArgumentError) no "400" json template defined for AppWeb.ErrorJSON  (the module does not exist)
    (phoenix_template 1.0.4) lib/phoenix/template.ex:248: Phoenix.Template.render_with_fallback/4
    (phoenix_template 1.0.4) lib/phoenix/template.ex:126: Phoenix.Template.render_to_iodata/4
    (phoenix 1.7.14) lib/phoenix/controller.ex:1008: anonymous fn/5 in Phoenix.Controller.template_render_to_iodata/4
    (telemetry 1.2.1) /home/psionicalch/Development/Elixir/OSS/twomillioncheckboxes/deps/telemetry/src/telemetry.erl:321: :telemetry.span/3
    (phoenix 1.7.14) lib/phoenix/controller.ex:974: Phoenix.Controller.render_and_send/4
    (phoenix 1.7.14) lib/phoenix/endpoint/render_errors.ex:86: Phoenix.Endpoint.RenderErrors.instrument_render_and_send/5
    (phoenix 1.7.14) lib/phoenix/endpoint/render_errors.ex:63: Phoenix.Endpoint.RenderErrors.__catch__/5
    (bandit 1.5.5) lib/bandit/pipeline.ex:124: Bandit.Pipeline.call_plug!/2

The project is also running phoenix version 1.7.14.

I think this issue with the project specific code rather than an issue with Phoenix. That's my bad, sorry.