Cannot render SVG using heex template

I have the following controller:

defmodule MyWeb.Admin.TagController do
  use Phoenix.Controller,
    formats: [:svg],
    layout: nil

  import Plug.Conn
  alias MyWeb.Admin.TagSVG

  def print(conn, %{"id" => id}) do
    conn
    |> put_status(200)
    |> render("print.svg")
  end
end

and the following html

defmodule MyWeb.Admin.TagSVG do
  use Phoenix.Component

  embed_templates("tag_svg/*")
end

and my svg:

<svg></svg>

But when I access the print method, I get this (I redacted cookies):

no function clause matching in Plug.Conn.resp/3

called with 3 arguments

    %Plug.Conn{adapter: {Bandit.Adapter, :...}, assigns: %{layout: false, current_user: %My.Accounts.User{__meta__: #Ecto.Schema.Metadata<:loaded, "users">, id: 1, inserted_at: ~U[2025-03-04 17:08:30Z], updated_at: ~U[2025-03-04 17:08:30Z], email: "xxx", encrypted_password: "xxx", password: nil}, flash: %{}}, body_params: %{}, cookies: %, halted: false, host: "dev.e42.ch", method: "GET", owner: #PID<0.13311.0>, params: %{"id" => "1"}, path_info: ["admin", "tags", "1", "print"], path_params: %{"id" => "1"}, port: 10008, private: %{:phoenix_template => "print.svg", :phoenix_view => %{"svg" => MyWeb.Admin.TagSVG}, MyWeb.Router => [], :phoenix_endpoint => MyWeb.Endpoint, :plug_session_fetch => :done, :plug_session => %{"_csrf_token" => "X6OvzuaBBLRMFEWVVtOqIqRS", "live_socket_id" => "users_sessions:dXNlcjox", "user_token" => "user:1"}, :before_send => [#Function<0.98198498/1 in Plug.CSRFProtection.call/2>, #Function<4.18939158/1 in Phoenix.Controller.fetch_flash/2>, #Function<0.9035112/1 in Plug.Session.before_send/2>, #Function<0.106864063/1 in Plug.Telemetry.call/2>, #Function<1.66608267/1 in Phoenix.LiveReloader.before_send_inject_reloader/3>], :phoenix_request_logger => {"request_logger", "request_logger"}, :phoenix_router => MyWeb.Router, :phoenix_action => :print, :phoenix_layout => %{_: {MyWeb.LayoutView, :app}}, :phoenix_controller => MyWeb.Admin.TagController, :phoenix_format => "svg", :phoenix_root_layout => %{"html" => {MyWeb.Layouts, :root}}}, query_params: %{}, query_string: "", remote_ip: {127, 0, 0, 1}, req_cookies: %, req_headers: [ {"cache-control", "no-cache"}, {"pragma", "no-cache"}, {"priority", "u=0, i"}, {"sec-fetch-site", "same-origin"}, {"sec-fetch-mode", "navigate"}, {"sec-fetch-dest", "document"}, {"upgrade-insecure-requests", "1"}, {"dnt", "1"}, {"referer", "https://dev.e42.ch:10008/admin/tags/1/print"}, {"accept-encoding", "gzip, deflate, br, zstd"}, {"accept-language", "en-US,fr-CH;q=0.7,en;q=0.3"}, {"accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"}, {"user-agent", "Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0"}, {"x-forwarded-proto", "https"}, {"x-forwarded-for", "2a12:bfc0:0:20::2:1"}, {"x-real-ip", "2a12:bfc0:0:20::2:1"}, {"host", "dev.e42.ch:10008"}], request_path: "/admin/tags/1/print", resp_body: nil, resp_cookies: %{}, resp_headers: [{"content-type", "image/svg+xml; charset=utf-8"}, {"cache-control", "max-age=0, private, must-revalidate"}, {"x-request-id", "GCpEBRZtUMll1NwAAL_G"}, {"referrer-policy", "strict-origin-when-cross-origin"}, {"x-content-type-options", "nosniff"}, {"x-download-options", "noopen"}, {"x-frame-options", "SAMEORIGIN"}, {"x-permitted-cross-domain-policies", "none"}], scheme: :http, script_name: [], secret_key_base: :..., state: :unset, status: 200}
    200
    %Phoenix.LiveView.Rendered{static: ["<!-- <MyWeb.Admin.TagSVG.print> lib/my_web/admin/tag_svg/print.svg.heex:1 (my) --><svg></svg><!-- </MyWeb.Admin.TagSVG.print> -->"], dynamic: #Function<0.93531985/1 in MyWeb.Admin.TagSVG.print/1>, fingerprint: 62811982155769489943919284070039046145, root: true, caller: :not_available}

It works with HTML format.

What am I missing?

https://hexdocs.pm/phoenix_template/1.0.4/Phoenix.Template.html

The section on format encoders.

1 Like

Aaaah, great thanks!