Inspect.Error message with colors

I fetched utc_now date like:

NaiveDateTime.utc_now

and I got:

~N[2017-01-06 19:28:39.656722]

so I tried to create a NaiveDateTime from its struct like:

result = %NaiveDateTime{day: 1, month: 1, year: 2017, hour: 0, minute: 0, second: 0.5}

and I got:

%Inspect.Error{message: "got ArgumentError with message \"argument error\" while inspecting \e[39m%{\e[0m\e[33m\e[36m__struct__: \e[0m\e[33m\e[36mNaiveDateTime\e[0m\e[33m\e[39m,\e[0m\e[33m \e[36mcalendar: \e[0m\e[33m\e[36mCalendar.ISO\e[0m\e[33m\e[39m,\e[0m\e[33m \e[36mday: \e[0m\e[33m1\e[39m,\e[0m\e[33m \e[36mhour: \e[0m\e[33m0\e[39m,\e[0m\e[33m \e[36mmicrosecond: \e[0m\e[33m\e[39m{\e[0m\e[33m0\e[39m,\e[0m\e[33m 0\e[39m}\e[0m\e[33m\e[39m,\e[0m\e[33m \e[36mminute: \e[0m\e[33m0\e[39m,\e[0m\e[33m \e[36mmonth: \e[0m\e[33m1\e[39m,\e[0m\e[33m \e[36msecond: \e[0m\e[33m0.5\e[39m,\e[0m\e[33m \e[36myear: \e[0m\e[33m2017\e[39m}\e[0m\e[33m"}

I was so surprised and tried to check it like:

IO.puts result.message

and was much more surprised when got:

** (KeyError) key :message not found in: %Inspect.Error{message: "got ArgumentError with message \"argument error\" while inspecting %{__struct__: NaiveDateTime, calendar: Calendar.ISO, day: 1, hour: 0, microsecond: {0, 0}, minute: 0, month: 1, second: 0.5, year: 2017}"}

After some thinking I understand that I can’t pass non-integer values to NaiveDateTime struct, but still I have some questions:

  1. Is it possible to change way of displaying message from Inspect.Error (of course without raise like above)?
  2. Can you explain me why I got KeyError?

My environment (iex output):

Erlang/OTP 18 [erts-7.3] [source] [64-bit] [smp:4:4] [async-threads:10]

Interactive Elixir (1.4.0)

I have installed Erlang from my package manager (emerge). I have also installed stable (for my distribution) version of Elixir (1.3.0-r1).

Elixir 1.4.0 is compiled from source like:

git clone git@github.com:elixir-lang/elixir.git
cd elixir
git checkout tags/v1.4.0
make clean test
./bin/iex # Here I'm experimenting

Because that exception does not have a message ‘value’, but probably a function or so. See this for more details (read that whole module doc actually :slight_smile: ).

Basically iex tried to display the improperly constructed %NaiveDateTime{} and thus failed, so you got puked an error. result is actually the thing that you constructed though, not that error, hence there would be no message key anyway. :slight_smile:

I have a guess, but unsure if I am correct (pretty sure I am not…), I’ll leave this one for someone else to answer. ^.^

It is an invalid %NaiveDateTime{} regardless though.

EDIT: Actually I am pretty sure I know why it is invalid, so I will just say regardless and someone can correct me otherwise. ^.^

The seconds is an integer, not a float, so 0.5 would not work (there is a microseconds tuple-field for that as I recall).

1 Like

No, when I copied that struct and call message on it then it works, but now I know why I have errors like that. It’s always NaiveDateTime, but cannot be inspected, so original struct is replaced by Inspect.Error struct all times - for all errors. So I can call methods on invalid NaiveDateTime struct. I think Elixir should raise in that case instead of return Inspect.Error struct. What do you think about it?

It is only an iex thing, you will not see it in actual compiled code unless you use inspect anywhere, of which inspect will only print the error, not return it (it should return the thing that is passed in only). The original struct is not replaced, rather when inspect is called (by iex to display it to you) it calls the calendar to convert it to a string, which then dies because seconds is a float instead of an integer, so inspect displays that error, but it does not change or replaced the original struct in any way. :slight_smile:

1 Like

I re-read &Kernel.inspect/2 and Inspect.Opts.
The final answer explains this code:

result = %NaiveDateTime{day: 1, month: 1, year: 2017, hour: 0, minute: 0, second: 0.5}
inspect(result, safe: false)

If struct that I try to work with is invalid then it will raise (it’s what I exactly want, because I now see what’s going wrong) instead of inspecting Inspect.Errror :smile:.
Now it’s much more clear for me. Thanks for explanations @OvermindDL1!

1 Like