Why is my 404 template rendering with the app.html.heex layout but not the root.html.heex layout?

The relevant config.exs section looks like this:

render_errors: [
    formats: [html: MyAppWeb.ErrorHTML, json: MyAppWeb.ErrorJSON],
    layout: false
  ],

Nothing I do in that config setting seems to have any effect on the layout situation for the 404 page. I have a 404.html.heex file at lib/my_app_web/controllers/error_html/404.html.heex, and error_html.ex looks like this:

defmodule MyAppWeb.ErrorHTML do
  use MyAppWeb, :html

  embed_templates "error_html/*"

  def render(template, _assigns) do
    Phoenix.Controller.status_message_from_template(template)
  end
end

My understanding is that best practice is for error templates to be entirely independent and render with no layout at all, but I can’t get it to use no layout or to use both root and app, which seems absolutely bizarre, because I can’t think of any context in which you’d want just app without root around it. I feel like I must be missing something obvious. I’m running Phoenix 1.7.2 if it matters.

According to the Custom Error Pages — Phoenix v1.7.2 guide, the render/2 function will override the template from embed_templates.

After you define the template file, remember to remove the equivalent render/2 clause for that template, as otherwise the function overrides the template. Let’s do so for the 404.html clause we have previously introduced in lib/hello_web/controllers/error_html.ex. We also need to tell Phoenix to embed our templates into the module:

+ embed_templates "error_html/*"

- def render("404.html", _assigns) do
-  "Page Not Found"
- end
1 Like

Changing that doesn’t seem to have any effect either. It is rendering the correct file, it’s just what it’s wrapping it with, layout-wise, that’s weird.

AH! FIGURED IT OUT!

I had some old code at the bottom of my router that was handling 404 issues specifically that I had completely forgotten about, so it wasn’t going through the usual pipeline at all.

1 Like