wktdev
How do I read Phoenix errors?
I’m playing a game where I intentionally create errors in my programs to see if I can fix them based on console output alone.
Cliff notes answer: I can’t
In JS I feel like errors are more direct and I can fix a program by finding the file and line number, and working backwards.
In Elixir I wouldn’t be able to fix a codebase that is handed to me from another developer without the help of forums and Google.
So for example, this error below is the result of me changing a function argument.
I went from this:
def handle_event("send", %{"text" => text}, socket) do # This is what I changed below
IO.inspect text
Phoenix.PubSub.broadcast(App.PubSub, topic, {:text_stuff, text})
{:noreply, socket}
end
To this
def handle_event("send", text, socket) do # This is what I changed
IO.inspect text
Phoenix.PubSub.broadcast(App.PubSub, topic, {:text_stuff, text})
{:noreply, socket}
end
The code is part of a larger Live View (below)
I would like to know how to use the errors to work backwards fix this. If anyone wants to share their thought process I would like to read it.
Error
`[error] GenServer #PID<0.1420.0> terminating
** (Protocol.UndefinedError) protocol Phoenix.HTML.Safe not implemented for %{"text" => "ad"} of type Map. This protocol is implemented for the following type(s): Atom, BitString, Date, DateTime, Decimal, Float, Integer, List, NaiveDateTime, Phoenix.HTML.Form, Phoenix.LiveComponent.CID, Phoenix.LiveView.Component, Phoenix.LiveView.Comprehension, Phoenix.LiveView.JS, Phoenix.LiveView.Rendered, Time, Tuple, URI
(phoenix_html 3.3.2) lib/phoenix_html/safe.ex:1: Phoenix.HTML.Safe.impl_for!/1
(phoenix_html 3.3.2) lib/phoenix_html/safe.ex:15: Phoenix.HTML.Safe.to_iodata/1
(app 0.1.0) lib/app_web/live/send_live.ex:38: anonymous fn/2 in AppWeb.SendLive.render/1
(phoenix_live_view 0.18.18) lib/phoenix_live_view/diff.ex:375: Phoenix.LiveView.Diff.traverse/7
(phoenix_live_view 0.18.18) lib/phoenix_live_view/diff.ex:544: anonymous fn/4 in Phoenix.LiveView.Diff.traverse_dynamic/7
(elixir 1.14.3) lib/enum.ex:2468: Enum."-reduce/3-lists^foldl/2-0-"/3
(phoenix_live_view 0.18.18) lib/phoenix_live_view/diff.ex:373: Phoenix.LiveView.Diff.traverse/7
(phoenix_live_view 0.18.18) lib/phoenix_live_view/diff.ex:139: Phoenix.LiveView.Diff.render/3
(phoenix_live_view 0.18.18) lib/phoenix_live_view/channel.ex:833: Phoenix.LiveView.Channel.render_diff/3
(phoenix_live_view 0.18.18) lib/phoenix_live_view/channel.ex:689: Phoenix.LiveView.Channel.handle_changed/4
(stdlib 4.2) gen_server.erl:1123: :gen_server.try_dispatch/4
(stdlib 4.2) gen_server.erl:1200: :gen_server.handle_msg/6
(stdlib 4.2) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
Last message: {:text_stuff, %{"text" => "ad"}}
State: %{components: {%{}, %{}, 1}, join_ref: "4", serializer: Phoenix.Socket.V2.JSONSerializer, socket: #Phoenix.LiveView.Socket<id: "phx-F3-xORYdOS-9swdH", endpoint: AppWeb.Endpoint, view: AppWeb.SendLive, parent_pid: nil, root_pid: #PID<0.1420.0>, router: AppWeb.Router, assigns: %{__changed__: %{}, flash: %{}, live_action: :home, message_item: ""}, transport_pid: #PID<0.1413.0>, ...>, topic: "lv:phx-F3-xORYdOS-9swdH", upload_names: %{}, upload_pids: %{}}`
Full LIve VIew Page
defmodule AppWeb.SendLive do
use AppWeb, :live_view
def mount(_params, _session, socket) do
if connected?(socket) do
Phoenix.PubSub.subscribe(App.PubSub, topic)
end
{:ok, assign(socket, message_item: "")}
end
def handle_info({:text_stuff, text}, socket) do
{:noreply, assign(socket, message_item: text)}
end
def handle_event("send", %{"text" => text}, socket) do # This is what I changed
IO.inspect text
Phoenix.PubSub.broadcast(App.PubSub, topic, {:text_stuff, text})
{:noreply, socket}
end
defp topic do #Topic
"message"
end
def render(assigns)do
~H"""
<div>
<h1>Send Message</h1>
<form phx-submit="send">
<input type="text" name="text" />
<button type="submit">Send</button>
</form>
<div>
<h1>ChatLive</h1>
<%= @message_item %>
</div>
</div>
"""
end
end
Most Liked
benwilson512
Sure! So when I read this I see that the top line is:
** (Protocol.UndefinedError) protocol Phoenix.HTML.Safe not implemented for %{"text" => "ad"} of type Map.
%{"text" => "ad"} sure looks like data from my app, so somewhere I’m giving Phoenix some data that isn’t HTML.Safe. Looking at the stack trace, the first few lines are in Phoenix code, but then I see
(app 0.1.0) lib/app_web/live/send_live.ex:38: anonymous fn/2 in AppWeb.SendLive.render/1
That’s code from my app, so let’s go check it out. Line 38 is
<%= @message_item %>
This is where I’m injecting the @message_item assign into the HTML. The error says that it isn’t HTML safe, so basically it’s telling me it isn’t allowed to just plop an Elixir map into HTML. Looking at my code I can see where I set message_item which is just:
def handle_info({:text_stuff, text}, socket) do
{:noreply, assign(socket, message_item: text)}
end
So somehow text is actually %{"text" => "ad"}. From there I’d look and see at what sends {:text_stuff and so on.
kokolegorille
benwilson512
Yeah Phoenix.HTML.Safe — Phoenix.HTML v4.3.0 is a bit terse but it does at least say:
In order to promote HTML safety, Phoenix templates do not use
Kernel.to_string/1to convert data types to strings in templates. Instead, Phoenix uses this protocol which must be implemented by data structures and guarantee that a HTML safe representation is returned.
The key bit is “to convert data types to strings in templates”. So if you get a ** (Protocol.UndefinedError) protocol Phoenix.HTML.Safe not implemented for error then that means it couldn’t convert it to a string in a template.
Popular in Questions
Other popular topics
Latest Phoenix Threads
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #hex
- #security









