Understanding SBCL Error Messages
When someone coming from Python or C++ starts using Common Lisp with SBCL, the first surprise is often the error messages. They look long, dense, and intimidating. There are many lines, strange function names, and references to internal components of the compiler. Unlike modern compilers such as Rust or Zig, SBCL does not show colorful arrows pointing at the exact line of code. Everything appears as plain text in the terminal.
At first glance this makes the errors look difficult to understand. But after studying many examples, a pattern appears. SBCL error messages actually follow a very regular structure. Once you understand that structure, the messages become much easier to read. To study this, I ran a small experiment. I wrote a collection of small Lisp programs that deliberately contain mistakes. These programs trigger different kinds of failures: undefined functions, type mismatches, syntax errors, wrong arguments, and so on. I then captured the error logs produced by SBCL and analyzed them.
This essay summarizes what those logs reveal and how someone new to Lisp can interpret them. You can find the code here.
The Overall Shape of an SBCL Error
Almost every SBCL error message has the same four parts.
- A headline describing the type of error
- A short explanation of what went wrong
- A stack trace (called a backtrace)
- A final line saying the program is quitting
At first the backtrace makes the error look intimidating, but the most important information is actually in the first few lines. For example, a typical error might begin like this:
Unhandled TYPE-ERROR: The value "a" is not of type NUMBER
Those two lines already explain the problem completely. The rest of the message simply provides extra debugging information. So the first lesson is simple: when reading SBCL errors, focus on the first few lines.
The First Line Tells You the Type of Problem
The first line of every error message contains the name of the error class. This is essentially the category of the problem.
Some common ones are:
UNDEFINED-FUNCTIONTYPE-ERRORDIVISION-BY-ZEROUNBOUND-VARIABLEFORMAT-ERRORINPUT-ERROR-IN-LOAD
You do not need to memorize these. Most of them are quite descriptive.
For example:
Unhandled UNDEFINED-FUNCTION: The function FOO is undefined.
This simply means the program tried to call a function that does not exist. Similarly the following means the program attempted to divide by zero.
Unhandled DIVISION-BY-ZERO
In practice, the error name almost always tells you what category of mistake occurred.
The Next Line Explains the Problem in Plain English
The second part of the error message usually describes the exact issue.
For example:
The value "a" is not of type NUMBER
This means a function expected a number but received a string instead. Another example:
The variable X is unbound
This means the program tried to use a variable that has not been defined. These explanations are usually clear and direct. You rarely need to look beyond them.
Many Lisp Errors Are Type Errors
One thing that becomes obvious after looking at many logs is that a large number of Lisp errors are type errors. A type error means a function received a value of the wrong kind.
Examples include:
- adding a number and a string
- using
caron a number - calling
lengthon a number - trying to treat a number like a list
For instance, the following code produces an error because car expects a list, not a number.
(car 10)
If you see a TYPE-ERROR, the solution is usually straightforward: check what kind of value the function expects and compare it with what you provided.
Some Errors Happen Before the Program Even Runs
Not all errors occur during execution. Some happen earlier, when Lisp is reading the source code. These are called reader errors. Examples include:
- missing parentheses
- incomplete files
- referring to a package that does not exist
In such cases SBCL prints something like:
READ error during LOAD
This means Lisp could not even understand the code structure.
In practice this usually means there is a syntax problem in the source file.
Sometimes the Compiler Warns You First
SBCL is not just an interpreter; it also performs compilation and analysis. Sometimes it can detect problems before the program actually runs. When that happens you may see warnings first, followed by a runtime error.
For example, if the compiler notices that a variable is likely to contain the wrong type of value, it may print a warning before execution continues. This behavior is similar to warnings produced by C++ compilers.
Argument Count Errors
Another type of failure occurs when a function receives the wrong number of arguments. For example:
(if 10)
In Lisp, if requires at least two arguments: a test and a result expression. Because only one argument was provided, SBCL produces an argument count error. The message may look complicated internally, but the real issue is simply that the function call has the wrong structure.
Package Errors
Common Lisp organizes symbols into packages, similar to namespaces in C++. SBCL protects important system symbols from accidental modification. If a program attempts to redefine a core function, SBCL stops it and prints an error. For example, trying to redefine car will trigger a package lock error. This is a safety feature to prevent accidental damage to the standard library.
The Backtrace
After the main error description, SBCL prints a backtrace. A backtrace shows the sequence of function calls that led to the failure. It is similar to a stack trace in Python or C++. The first entry in the backtrace is usually the most relevant one because it shows the expression that failed. Everything after that often refers to internal parts of SBCL. Beginners do not need to read the entire backtrace. Looking at the first one or two entries is usually enough.
Why the Errors Look So Long
SBCL error messages are long because the system exposes a lot of internal detail. This detail is extremely useful when debugging complex programs, but it can look overwhelming when you first encounter it. Modern programming languages often hide this information behind a cleaner interface with colored highlights and arrows pointing to source lines. SBCL takes a different approach: it prints the raw diagnostic information. The good news is that most of this output can safely be ignored until you need it.
A Simple Strategy for Reading SBCL Errors
When you encounter an error in SBCL, use the following steps:
- Read the first line to identify the error type
- Read the explanation in the next line
- Look at the first entry in the backtrace
- Ignore the rest unless the problem is complicated
Following this simple approach makes most SBCL errors easy to interpret.
Final Thoughts
Although SBCL error messages initially look intimidating, they are actually quite systematic. Every message follows a predictable structure and usually explains the problem clearly in the first few lines. For programmers coming from Python or C++, the biggest adjustment is simply learning to ignore the large amount of internal detail printed after the main explanation. Once you focus on the headline and the short description of the problem, SBCL errors become much easier to understand. In fact, the system provides more debugging information than many modern programming environments. It simply presents that information in a very raw form.