Skip to content

Error format data structure #1

@roberth

Description

@roberth
Scope

I'm proposing to pay extra attention to the use of (semi)structured data for error messages. Considering that the plan is to update many if not all error messages, this seems like the right time to make sure those errors are usable by programs too, without duplicating effort.

This rest of this issue sketches out a broad scope, but for this to be effective, the most important action is to rewrite the exceptions into a well-designed C++ data structure that preserves the underlying structure until it is formatted by a generic error formatter.

Structured data for integrations

Errors are currently stringly typed. This poses a challenge for tooling that needs to use the messages, such as IDE integrations.
For example, Nix has many exceptions like this that essentially throws away the source position by converting it to text.

throw EvalError(format("cannot import '%1%', since path '%2%' is not valid, at %3%")
        % path % e.path % pos);

A related problem exists on the Nix language side. Through primops like builtins.throw, Nix only exposes stringly typed error messages. This has been stretched to include terminal color codes,

Structured data for emitters

The Nix language currently allows the programmer to emit custom errors, warnings and stack trace items, but they only allow text. This has been stretched to include terminal color codes to create an appearance of consistency, but to programs it is still text. In their current form, the builtins require a reimplementation of the error formatting.

Single data structure?

Both of these use cases can be solved with the right data structures. I expect these to be the same if not very similar. The format for integrations should be serializable as JSON and Nix language values are very similar to JSON. One possible difference is that the builtins may need to take in some hints where to gather extra information, because not all information is exposed to Nix programs, to avoid impurities.

Example Nix exception

builtins.throw {
  range = m.file;
  errorName = "Option does not exist.";
  toolName = "module system"; # LSP calls this `source`
  message = [
    "The option "
    { highlight = "wrong"; text = showOption (prefix ++ [name]); }
    " does not exist. You can only define values for options that have been declared. See the"
    { text = "manual"; link = "https://nixos.org/nixos/manual/index.html#sec-option-definitions"; }
    " for more."
  ];
};

The Language Server Protocol Diagnostic may be a good source of inspiration for the format, to keep the vocabulary similar and the conversions simple. However, some deviation is for the better. For example string constants are easier to work with than magic integers from a spec.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions