Understanding Elixir error messages and stack traces
It's important to understand what your application's error type is telling you when debugging an issue.
In this article, we'll cover common Elixir error types and what your application tells you when encountering one.
We'll also show you how AppSignal helps thousands of developers capture and monitor these errors in real-time, giving you the insights needed to quickly pinpoint problems.
How to read an error message
Error messages are most often output in the following format:
** (ErrorCode) description
file_location:line_number: (error_location)For example, considering the following example:
** (ArgumentError) argument error
publisher.exs:5: (file)We can deduce the following:
- Error location: line 5 of the publisher.exs:5 file in the
publishfunction call in thepublish_articlefunction - Error type: ArgumentError
- Error Message: wrong number of arguments (given 3, expected 2)
Which can be understood as: "On line 5, in the publish_article function in the publisher.exs file, three arguments were passed to the publish function instead of two"
With AppSignal, you can automatically capture and monitor errors, including their stack traces, giving you real-time visibility into issues as they occur:

How to read a stack trace
Whenever an error occurs in your application, Elixir will raise an exception and log a stack trace, which you can then use to find the location of an error within your application's code.
In Elixir, if you try and divide a number by zero, you will raise a ArithmeticError. To demonstrate a stack trace, let's raise one:
# maths_is_hard.exs
defmodule MathsIsHard do
def divide(x, y) do
IO.puts("#{x} divided by #{y} is #{x / y}")
end
end
MathsIsHard.divide(8, 0)In the above code snippet, we've defined a function called divide(a, b), which will divide any two integers we provided. Let's execute the code in our terminal to raise ArithmeticError and print a stack trace:
$ elixir maths_is_hard.exs
** (ArithmeticError) bad argument in arithmetic expression
maths_is_hard.exs:3: MathsIsHard.divide/2
(elixir 1.13.4) lib/code.ex:1183: Code.require_file/2So, what is our stack trace telling us? Let's look at it line per line:
- The first line tells us: an ArithmeticError has been raised due to a bad argument.
- The second line tells us: the divide function was called on line 2 of the
maths_is_hard.exsfile. - The third line tells us: Tell us that the error occurred in the elixir standard library
(elixir 1.13.4)during runtime. You may see a slightly different error depending on what package your application is using, for example, if an error occurs while loading a Phoenix function.
We can use this stack trace to deduce where the error was raised in our code and where the function was called.
When AppSignal captures an error, you can inspect critical error details, including the full backtrace, to quickly identify and resolve issues:

In the case of the example above, we know the issue was caused by 0 being passed as an argument on maths_is_hard.exs:3. We could then make sure not to pass 0 as an argument or modify our function to safely return a message if 0 is passed as an integer:
defmodule MathsIsHard do
def divide(x, y) do
if y > 0 do
IO.puts("#{x} divided by #{y} is #{x / y}")
else
IO.puts("You can't divide by 0")
end
end
end
MathsIsHard.divide(8, 0)Which would output the following when run:
$ elixir maths_is_hard.exs
You can't divide by 0
Good to know: We're using shorter stack traces here for brevity, but your application's stack trace will often be much longer. However, the same logic to reading stack traces applies, regardless of length.
How AppSignal helps you fix errors faster
AppSignal's Error reporting automatically captures error details, including stack traces, so you don't have to spend time manually digging through logs. With AppSignal, you get immediate insights and actionable data, empowering you to resolve issues faster.
| Feature | Without AppSignal | With AppSignal |
|---|---|---|
| Tracking errors | Manually searching through logs and stack traces | Automatically captured and organized by AppSignal |
| Error notifications | Checking logs manually for errors | Instant real-time alerts for any error |
| Context and metadata | Limited details from the error message and stack trace | Rich context like with request data, tags, trends and more |
| Fixing errors | Manually finding error causes | AppSignal provides actionable insights for quick resolutions |
Common error types
ArgumentError
ArgumentError is raised when you call a function with the incorrect type of argument.
For example, say you want to convert a string into an integer; Elixir would expect a "textual representation of an integer" like 1, 300 or541 , and not a word representation of an integer like "one", "three-hundred", "five-hundred-and-one" etc:
iex(1)> String.to_integer("one")
** (ArgumentError) errors were found at the given arguments:
* 1st argument: not a textual representation of an integer
:erlang.binary_to_integer("one")Resolution:
To resolve this error, check what arguments the function is expecting and ensure you pass those arguments when calling the function in your code:
iex(2)> String.to_integer("12")
12Note: If you are curious about what arguments a function expects in Elixir, you can use the helper function in your iex console, for example:
iex(3)> h(String.to_integer())will return the following output, with argument information and error expectations:
def to_integer(string)
@spec to_integer(t()) :: integer()
Returns an integer whose text representation is string.
string must be the string representation of an integer.
Otherwise, an ArgumentError will be raised. If you want to parse
a string that may contain an ill-formatted integer, use
Integer.parse/1.
Inlined by the compiler.
## Examples
iex> String.to_integer("123")
123
Passing a string that does not represent an integer leads to an
error:
String.to_integer("invalid data")
** (ArgumentError) argument errorFunctionClauseError
In Elixir, a single function can have multiple clauses defined via pattern matching and guards.
A FunctionClauseError is raised when a function is called with clauses that do not match the function's expectations.
We speak a lot of languages in AppSignal, so we've created some Elixir code to greet everyone in their native tongue:
defmodule Greeter do
def hello(:dutch, name) do
IO.puts("Hallo #{name}!")
end
def hello(:english, name) do
IO.puts("Hello #{name}!")
end
def hello(:spanish, name) do
IO.puts("¡Hola #{name}!")
end
endWhen we call the Greeter.hello function, Elixir will scan the file for a function with a clause that matches the arguments we've provided. If there is no matching clause, then we'll get a FunctionClauseError, for example, let's try and greet someone in Serbian:
iex(2)> Greeter.hello(:serbian, "Milica")
** (FunctionClauseError) no function clause matching in Greeter.hello/2
The following arguments were given to Greeter.hello/2:
# 1
:serbian
# 2
"Milica"
iex:2: Greeter.hello/2Resolution
To resolve this error, we'll need to add a function clause that matches, so in the above example, a function clause that accepts four arguments:
def hello(:serbian, name) do
IO.puts("zdravo #{name}!")
endKeyError
A KeyError occurs when trying to access a key that does not exist, for example, when trying to access the non-defined author key in the below article_attributes map:
article_attributes = %{title: 'Elixir is awesome', header: 'elixir.png'}The following error would be returned:
iex(1)> Map.fetch!(article_attributes, :author)
** (KeyError) key :author not found in: %{header: 'elixir.png', title: 'Elixir is awesome'}
(stdlib 3.16.1) :maps.get(:author, %{header: 'elixir.png', title: 'Elixir is awesome'}Resolution
To resolve this error, you need to ensure you're fetching keys that exist in a map or use a function that does not raise an error when a key is not found. You can always list the available keys using the Map.keys() function:
iex(1)> Map.keys(article_attributes)
[:header, :title]
iex(2)> Map.fetch!(article_attributes, :title)
'Elixir is awesome'To see if a specific key exists, you can use the has_key?(map, key) function:
article_attributes = %{title: 'Elixir is awesome', header: 'elixir.png'}
iex(1)> Map.has_key?(article_attributes, :author)
falseThe get(map, key) function allows us to get keys from a map without raising an error if the key doesn't exist:
iex(1)> Map.get(article_attributes, :author)
nil
iex(2)> Map.get(article_attributes, :author, "Jane Doe")
"Jane Doe"UndefinedFunctionError
UndefinedFunctionError is raised when you call a function that is not defined. In the example below, we call the publish_article function on the Article module; however, no publish_article function is defined:
# articles_controller.exs
def publish_article(article) do
article.publish_article(article)
endWhich, when executed, will result in the following error:
** (UndefinedFunctionError) function Article.publish_article/0 is undefined or private
Article.publish_article()Resolution
To resolve the error, a function exported by the module must be invoked.
We can check the file where our Article module is defined, and we can use the module_info function to see what functions the Article module exports:
iex(1)> Article.module_info
[
module: Article,
exports: [
__info__: 1,
publish: 1,
...Let's use the publish() function:
iex(2)> Article.publish(article)
{:ok,
%PhoenixApp.Article{
__meta__: #Ecto.Schema.Metadata<:loaded, "articles">,
id: 1,
inserted_at: ~N[2023-06-28 10:01:37],
published: true,
title: "The Elixir of Life",
updated_at: ~N[2023-06-28 10:01:37]
}}Never miss an exception with AppSignal
With AppSignal Error Reporting, AppSignal can record and notify you when errors occur, helping you quickly resolve problems in your application's codebase.

AppSignal's Error Reporting is just one of our many developer-driven features that help you get the most out of monitoring your application. Developers also enjoy using our monitoring because we offer:
- An intuitive interface that is easy to navigate.
- Simple and predictable pricing.
- Developer-to-developer support.
Ready to take control of your Elixir app's errors? Start your free trial with AppSignal today!
Make your next crash make sense.
Free for 30 days. No credit card. Two-minute install.