error message

Outputting Error Messages #

toml11 provides error messages that include location information within the file when using functions like toml::parse, toml::get<T>/find<T>, and as_integer(), among others.

For instance, if a syntax error in an integer is detected during parsing, an error message might look like this:

[error] bad integer: `_` must be surrounded by digits
 --> internal string at line 64 in file main.cpp
   |
 1 | a = 123__456
   |        ^-- invalid underscore
Hint: valid  : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755
Hint: invalid: _42, 1__000, 0123

Or, if a type different from the one actually stored is requested:

[error] toml::value::as_string(): bad_cast to string
 --> input.toml
   |
 1 | a = 123_456
   |     ^^^^^^^-- the actual type is integer

toml11 provides methods to create such error messages from toml::value.

By utilizing this feature, you can inform users not only about TOML syntax errors but also about application-specific errors. For example, if a negative number appears where only positive values are allowed, you can highlight the location within the TOML file to convey the error to the user.

Creating Error Messages from toml::value Location Information #

toml::value retains information about the location where it was parsed.

This information is encapsulated in toml::source_location and can be retrieved using toml::value::location().

const toml::value& a = input.at("a");
const toml::source_location src = a.location();

When a file is parsed with toml::parse, the TOML filename and line numbers are stored.

If parsed with toml::parse_str, the TOML filename is not available, but instead, the filename and line number of the C++ source code that called toml::parse_str are stored as the TOML filename. The first example on this page was output from toml::parse_str. Note the filename part.

For details, see the reference.

You can build error information by passing a toml::source_location or toml::value and the associated error message to toml::make_error_info. Passing this to toml::format_error formats the error message into a std::string.

const toml::value& a = input.at("a");
if(a.as_integer() < 0)
{
    const toml::error_info err = toml::make_error_info(
            "positive integer is required", // Error title
            a, "but got negative value"     // Message next to the value
        );
    std::cerr << toml::format_error(err) << std::endl;
}

This will output:

[error] positive integer is required
 --> input.toml
   |
 1 | a = -123456
   |     ^^^^^^^-- but got negative value

You can also add a supplementary message at the end. This part is not indented.

const toml::value& a = input.at("a");
if(a.as_integer() < 0)
{
    const toml::error_info err = toml::make_error_info(
            "positive integer is required",      // Error title
            a, "but got negative value",         // Message next to the value
            "Hint: `a` means length of the data" // Supplementary message
        );
    std::cerr << toml::format_error(err) << std::endl;
}

This will output:

[error] positive integer is required
 --> input.toml
   |
 1 | a = -123456
   |     ^^^^^^^-- but got negative value
Hint: `a` means length of the data

The ability to output lines from the file using toml::value is because the parsed file is retained in memory as a string.

The parsed string is shared by toml::value via a std::shared_ptr. Copying it does not duplicate the entire file string. The file information is freed from memory when all toml::value instances constructed from parsing the file are destructed.

Therefore, when using this in an application, it is recommended to extract and store the required values during loading rather than directly storing toml::value.

Adding Colors to Strings #

You can add color to error messages using ANSI escape codes.

If TOML11_COLORIZE_ERROR_MESSAGE is defined at compile time, the error messages output by toml11 will be colored by default.

If not, you can enable color for subsequent error messages by calling toml::color::enable(). Conversely, if you do not want colored output, for example, because the output is not to a console, call toml::color::disable(). You can check whether coloring is enabled at any point by calling toml::color::should_color().

Additionally, while the error title, error message, and supplementary information are not colored by default, you can use manipulators from toml::color to add color to them.

std::ostringstream oss;
oss << toml::color::red << "but got negative value";

const toml::error_info err = toml::make_error_info(
        "positive integer is required",      // Error title
        a, oss.str(),                        // Message next to the value
        "Hint: `a` means length of the data" // Supplementary message
    );

For more details, see the reference.

Changing the Prefix of Error Messages from [error] #

There may be different types of errors, and the default [error] prefix might not always be appropriate.

With toml::format_error, you can provide a std::string before toml::error_info to replace the [error] prefix.

For example:

const toml::value& a = input.at("a");
if(a.as_integer() < 0)
{
    const toml::error_info err = toml::make_error_info(
            "positive integer is required", // Error title
            a, "but got negative value"     // Message next to the value
        );

    std::ostringstream prefix;
    prefix << toml::color::bold << toml::color::yellow << "[warn]";
    std::cerr << toml::format_error(prefix.str(), err) << std::endl;
    return 0;
}
else
{
    return a.as_integer();
}

This will output a warning starting with [warn].

Additionally, you can create error messages without the [error] prefix by directly passing the components of error_info to toml::format_error.

const toml::value& a = input.at("a");
if(a.as_integer() < 0)
{
    std::cerr << toml::format_error(
            "[warn] positive integer is required", // Error title
            a, "but got negative value"            // Message next to the value
        ) << std::endl;
    return 0;
}
else
{
    return a.as_integer()
}

Creating Error Messages Referencing Multiple toml::value #

In application settings, the range of permissible values might change based on previously read values.

In such cases, you may want to output the values causing the error simultaneously.

toml::format_error and toml::make_error_info can take multiple pairs of toml::value and their corresponding error messages as std::string.

std::cerr << toml::format_error(
        "[error] invalid range",
        a, "minimum value is defined here",
        b, "maximum value is defined here",
        c, "and it exceeds the range"
    ) << std::endl;

You can also add supplementary information at the end.

std::cerr << toml::format_error(
        "[error] invalid range",
        a, "minimum value is defined here",
        b, "maximum value is defined here",
        c, "and it exceeds the range",
        "Hint: all the values must be in the range [a, b)"
    ) << std::endl;

When passing toml::value or toml::source_location, an error message related to it must follow. If not, it will result in a very confusing compilation error.