Yesterday I was building a simple Elixir app using cowboy
and Plug
, and was trying to fix a strange issue. My POST requests with JSON body was simply… disappearing.
It took me an hour of poking at wrong places to find out that I actually forgot to add poison
dependency, which I was using as JSON decoder, in mix.exs
. Once I fetched that dependency, it worked as expected.
The strange thing was that the error message was not being shown anywhere. After tinkering with it a bit more, I found out that Plug.Parsers.ParseError
would not show up in trace even with poison
dependency added.
This seems like a reasonable decision, since I wouldn’t want my error log to be overwhelmed by all the errors from http requests with incorrectly formatted JSON. Well, aside from a minor issue that cowboy
automatically sends 500 Internal Server Error
status when 400 Bad Request
is more appropriate in this case.
But I’m curious about how the error was not being propagated up the stack trace and/or process supervision tree. Where is it going? Where is it being caught and discarded? How is it being discarded? Can someone help me look into this?
1 Like
I’m pretty sure it is being passed to the ErrorView render functions, the error exception should be in the assigns.reason
considering I have code like this:
def render("403.html", assigns) do
case assigns[:reason] do
%Perms.PermissionException{} = exc ->
Logger.warn("Permission Error of #{inspect exc.permission} due to #{inspect assigns[:conn]}")
"Forbidden due to permission error: #{exc.message}"
_ -> "Forbidden"
end
end
Although this specific render function is no longer called since I added a plug (no way to redirect from a view, there really should be…) that redirects to the login page on a permission error. ^.^
Exceptions will be a status 500 by default, but you can add a plug_status member or override a protocol to specify whatever status you want an exception to be. I have plug_status’s on all my exceptions.
Now if only we could specify a protocol or something that acts as a controller level callback for an exception instead of going straight to the view, hmm, that might actually be pretty easy to do now that I think of it, will require a controller override plug (I already have a few of those, wrapping a controller handler is not so fun…).
1 Like
Thanks to your hints, I started digging more into it with tools like :debugger
. Then I found Plug.Debugger
and Plug.ErrorHandler
that allow me to have a better look at the errors - they would come quite handy when I want to look at errors from Plug
. I think I will stop venturing into this rabbit hole for now. Thank you for helping!
1 Like