Handling errors
editFind the error in the document
Invalid TOML, and a document that does not match your types, throw a TomlException. It gives the location of the first error: SourceName, Line and Column (1-based), Offset (0-based) and Span. Set SourceName in the options to put the file name in the messages:
var toml = """
Host = "example.com"
Port = "https"
""";
var options = new TomlSerializerOptions { SourceName = "server.toml" };
var exception = Assert.Throws<TomlException>(() => TomlSerializer.Deserialize<ServerConfig>(toml, options));
Assert.Equal("server.toml", exception.SourceName);
Assert.Equal(2, exception.Line);
Assert.Equal(8, exception.Column);Diagnostics lists every error. Reading does not stop at the first mapping error: a value that cannot be converted, an invalid collection element or a missing required key is recorded, and the rest of the document is read, so a user can fix all the errors of a file at once. Reading stops after 1,000 errors.
Expect invalid input
TryDeserialize returns false instead of throwing when the input is not valid TOML or does not match the model. It is available for every input type, with options or with a source-generated context:
var toml = "Port = \"not a number\"";
var success = TomlSerializer.TryDeserialize<ServerConfig>(toml, out var config);
Assert.False(success); // Invalid input
Assert.Null(config);- It also returns
falsewhen the result isnull. - It stops at the first error, as it does not report them. Use Deserialize and catch the TomlException to show the errors to the user.
- It still throws for errors of the program, such as a type that has no metadata in the context, or a converter that reads too much or too little.
- An exception thrown by your model, such as a setter or an ITomlOnDeserialized callback that validates a value, is not caught, like in
System.Text.Json. An exception thrown by a constructor is reported as a TomlException.
Read untrusted input
A document sent by a user can be large or deeply nested. Set limits on the options you use to read it:
var options = new TomlSerializerOptions
{
MaxInputLength = 64 * 1024, // characters for a string, bytes for a Stream
MaxDepth = 16,
UnmappedMemberHandling = TomlUnmappedMemberHandling.Disallow,
};
var toml = """
Host = "example.com"
Timeout = 30
""";
var success = TomlSerializer.TryDeserialize<ServerConfig>(toml, out var config, options);
Assert.False(success); // Timeout is not a member of ServerConfig
Assert.Null(config);- MaxInputLength rejects a document that is too long before it is loaded: a
TextReaderor aStreamis not read further. It counts characters for a string or aTextReader, and bytes for aStream. There is no limit by default. - MaxDepth limits the nesting of tables and arrays, 64 by default. A document nested deeper than the stack of the current thread allows throws a TomlException instead of overflowing the stack.
UnmappedMemberHandling = TomlUnmappedMemberHandling.Disallowrejects keys that your model does not expect.- TomlSerializer reads with less memory than the syntax tree, which keeps every character of the input as an object: read untrusted input with the serializer or with TomlParser.
Errors of the values
Some values that TOML accepts cannot be held by .NET types, and some .NET values cannot be written as TOML. Each throws a TomlException:
- A float that overflows a
double, a leap second, the year0000, or an offset beyond ±14:00, when reading. See TOML 1.0 and 1.1. - A
nullmember that is not skipped, an integer outside the range oflong, or aTimeSpanthat is negative or of 24 hours or more, when writing. See Serializing objects.