The Erlang Error Index is a catalogue of errors emitted by
various tools within the Erlang ecosystem, including - but not limited
to - the erlc
Erlang compiler and the dialyzer
type checker.
The catalogue is not limited to tools shipped with Erlang/OTP, but it can include third-party applications such as the EqWAlizer type-checker or the Elvis code style reviewer.
Each error in the catalogue is identified by a unique code and it is accompanied by a description, examples and possible courses of action. Error codes are namespaced based on the tool that generates them. Unique codes can be associated to a human-readable alias.
Unique error codes can be leveraged by IDEs and language servers to provide better contextual information about errors and make errors easier to search and reference. A standardized error index creates a common space for the Community to provide extra examples and documentation, creating the perfect companion for the Erlang User Manual and standard documentation.
The concept of an “Error Index” for a programming language is not a novel idea. Error catalogues already exist, for example, in the Rust and Haskell Communities.
Producing meaningful error messages can sometimes be challenging for developer tools such as compilers and type checkers due to various constraints, including limited context and character count.
By associating a unique code to each diagnostic (warning or error) we relief tools from having to condense a lot of textual information into a - sometime cryptic - generic, single sentence. Furthermore, as specific wording of errors and warnings is improved over time, error codes remain constant, providing a search-engine friendly way to index and reference diagnostics.
An good example of this is the expression updates a literal error message, introduced in OTP 27. Given the following code:
-define(DEFAULT, #{timeout => 5000}).
updated(Value) ->
?DEFAULT#{timeout => Value}.
The compiler emits the following error:
test.erl:8:11: Warning: expression updates a literal
% 8| ?DEFAULT#{timeout => 1000}.
% | ^
The meaning of the error may not be obvious to everyone. Most importantly, the compiler provide no information on why the warning is raised and what a user could do about it. The user will then have to recur to a search engine, a forum or equivalent to proceed.
Conversely, we can associate a unique identifier to the code (say,
ERL-1234
):
test.erl:8:11: Warning: expression updates a literal (ERL-1234)
% 8| ?DEFAULT#{timeout => 1000}.
% | ^
The code make it possible to link the error message to an external resource (e.g. a wiki page), which contains all the required, additional, information about the error that would not be practical to present directly to the user. Here is an example of what the entry could look like for the above code:
Unique error codes also have the advantage to be better searchable in forums and chats, where the exact error message could vary, but the error code would be the same.
Finally, error codes can be used by IDEs (e.g. via language servers) to match on error codes and provide contextual help. Both the Erlang LS and the ELP language server already use “unofficial” error codes.
To make it easier for language servers and IDEs, tools producing
diagnostics should produce diagnostics (errors and warnings) in a
standardized format. In the case of the compiler, this could be done
by specifying an extra option (e.g. --error-format json
).
A possible JSON format, heavily inspired by the LSP protocol, is:
{
uri: "file:///git/erlang/project/app/src/file.erl",
range: {
start: {
line: 5,
character: 23
},
end: {
line: 5,
character: 32
}
},
severity: "warning",
code: "DIA-1234",
doc_uri: "https://errors.erlang.org/DIA/DIA-1234",
source: "dialyzer",
message: "This a descriptive error message from Dialyzer"
}
Where:
error
, warning
, information
, hint
.An error code should be composed by two parts: an alphanumeric
namespace (three letters) and a numeric identifier (four digits),
divided by a dash (-
).
A potential set of namespaces could look like the following:
Namespace | Description |
---|---|
ERL | The Erlang compiler and related tools (linter, parser, scanner) |
DIA | The Dialyzer type-checker |
ELV | The Elvis code-style reviewer |
ELP | The Erlang Language Platform |
… | … |
A set of potential error codes could look like:
ERL-0123
DIA-0009
ELV-0015
ELP-0001
The exact number of characters/digits for each namespace and code is
open for discussion, as well as the fact whether components such as
the parser, the scanner or the erlint
Erlang linter should have
their own namespace.
The Erlang/OTP team would be ultimately responsible for maintaining a list of official namespaces. Each tool maintainer would then be responsible to allocate specific codes to specific diagnostics.
The error index can be implemented in the format of Markdown pages. The approval process for a namespace (or an error code) will follow a regular flow using a Pull Request, reviewed and approved by the Erlang/OTP team and, potentially, other interested industrial members.
Errors cannot be re-used. If a tool stops emitting an error code, the deprecated error code is still documented in the index, together with a deprecation notice. This is to avoid re-using a single code for multiple purposes.
To limit the administration burden, the section will contain only error codes for the tools shipped with Erlang/OTP and the namespaces for external tools. Individual error codes for each namespace would be managed by the respective owners.
The ELP website contains a proof of concept of what an Erlang
Error Index could look like. Ideally, such a website would live under
the erlang.org
domain, e.g. using the https://errors.erlang.org/
URL.
The website should use Markdown as the primary mechanism to write content and it should be easily extensible by the Community.
This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive.