jaimeiniesta

jaimeiniesta

Rescuing from an Erlang error

Hello, I’ve tried 2 libraries for parsing XML: sweet_xml and quinn, and both rely on the Erlang package xmerl.

They both work great, but when they encounter malformed XML, they error and exit like this:

iex(4)> Quinn.parse "<xml>"
** (exit) {:fatal, {:unexpected_end, {:file, :file_name_unknown}, {:line, 1}, {:col, 6}}}
16:21:51.714 [error] 4108- fatal: :unexpected_end
xmerl_scan.erl:4111: :xmerl_scan.fatal/2
xmerl_scan.erl:572: :xmerl_scan.scan_document/2
xmerl_scan.erl:288: :xmerl_scan.string/2
lib/xml_parser/xml_parser.ex:5: Quinn.XmlParser.parse/1

If I directly use :xmerl_scan.string/1 I get the same error:

iex(1)> :xmerl_scan.string '<xml>'
** (exit) {:fatal, {:unexpected_end, {:file, :file_name_unknown}, {:line, 1}, {:col, 6}}}
16:36:46.245 [error] 4108- fatal: :unexpected_end
xmerl_scan.erl:4111: :xmerl_scan.fatal/2
xmerl_scan.erl:572: :xmerl_scan.scan_document/2
xmerl_scan.erl:288: :xmerl_scan.string/2

Now, I want to make my app rescue from this error, but I’m not being able to do this. I’ve tried this but it doesn’t work:

iex(1)> try do
...(1)>   :xmerl_scan.string '<xml>'
...(1)> rescue
...(1)>   RuntimeError -> "Error!"
...(1)> end
** (exit) {:fatal, {:unexpected_end, {:file, :file_name_unknown}, {:line, 1}, {:col, 6}}}

iex(1)>
16:40:20.003 [error] 4108- fatal: :unexpected_end

I suppose that it’s because it’s not a RuntimeError I’m dealing with, because it’s not from Elixir, but Erlang. I can catch the exit, however.

How can I rescue from this error?

Thanks!

Marked As Solved

OvermindDL1

OvermindDL1

Easiest thing would be just to set a new group leader for its (yours? If run in the same process, I don’t know if it is or not) process.

It should be able to be done via:

f = get_empty_group_leader() # Implement this yourself as a supervised GenServer somewhere
:elixir.group_leader(f, self()) # Or instead of self() use whatever is the PID of the xmerl process

The part you need to implement yourself of get_empty_group_leader() just use a GenServer somewhere that implements the file streaming erlang protocol (see erlang docs), or have it basically ignore everything (I think you need to send :ok back or something on a few of them though).

Also Liked

OvermindDL1

OvermindDL1

It is not ‘raising’ an error, so rescue will not handle it. It is ‘throwing’ an :exit, so you need to catch it like:

iex> try do
...>   exit "I am exiting"
...> catch
...>   :exit, _ -> "not really"
...> end
"not really"

And that is the only way to handle an exit in that context (without looking at xmerl itself, if it is another process then trapping exits would work too).

EDIT: Or more accurately for your use case:

iex(2)> try do
...(2)>  :xmerl_scan.string '<xml>'
...(2)> catch
...(2)>  :exit, e -> {:nope, e}
...(2)> end
[error] 4108- fatal: :unexpected_end

{:nope,
 {:fatal,
  {:unexpected_end, {:file, :file_name_unknown}, {:line, 1}, {:col, 6}}}}
alecnmk

alecnmk

Greetings,

Actually there is event simpler solution(s).

  1. xmerl_scan has quiet ({quiet, Flag}) as one of the options. When set to true xmerl behaves and nothing get’s error-logged. Details are here: http://erlang.org/doc/man/xmerl_scan.html

  2. I was experiencing same issue with false error reporting as @jaimeiniesta. And that’s Elixir Logger capturing erlang’s standard_error and logs it with error level to configured Logger backends. See :handle_otp_reports config option of the Elixir.Logger

  3. Solution with wrapping xmerl parsing in a separate process and setting group leader to stub GenServer didn’t work for me. But good implementation example could be found in ExUnit Capture logs/io sources: https://github.com/elixir-lang/elixir/blob/master/lib/ex_unit/lib/ex_unit/capture_io.ex

Cheers

jaimeiniesta

jaimeiniesta

For the record, SweetXml allows passing options to xmerl when parsing:

https://hexdocs.pm/sweet_xml/SweetXml.html#parse/2

SweetXml.parse(doc, quiet: true)
jaimeiniesta

jaimeiniesta

Thanks @OvermindDL1 - that’s what I’m doing, catching the :exit, but I also see the [error] 4108- fatal: :unexpected_end line, I thought an error was being raised and I was unable to catch it.

But, what I think it’s happening here is that the error just gets logged, no error is raised. Does that make sense?

OvermindDL1

OvermindDL1

Actually that [error] part is a logged message from xmerl, not even really an error message, not a thrown anything, just a bit of noise from an old erlang module. You could silence it by hooking its output if you really want. :slight_smile:

Where Next?

Popular in Questions Top

_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
Werner
Hi, I’m using Ubuntu 18.04 and after updating to OTP-24.0 yesterday i have this warning when I run “mix local.hex”: 14:57:30.512 [warn] ...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod -- where is this set? Thanks.
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
hpopp
To simplify some tasks at work, I wrote and published this package yesterday. It’s a simple macro that enables Access behaviour on struct...
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
wernerlaude
In AR this is so simple @articles = current_user.articles How to do in Ecto? def index(conn, _params) do current_user = conn.assig...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New

Other popular topics Top

senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
yawaramin
In the Dialyzer docs ( http://erlang.org/doc/man/dialyzer.html#requesting-or-suppressing-warnings-in-source-files ), there is a way to tu...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
beno
I will often find my self writing things similar to: case some_value do nil -&gt; something() "" -&gt; something() _ -&gt; someth...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New

We're in Beta

About us Mission Statement