Skip to main content
Version: 0.2.x (0.2.1)

Error codes and exceptions

A rejected value always carries two things: a stable, machine-readable code, and a human-readable message. The code is the contract — it reaches problem details responses and FluentValidation failures, and a client may branch on it. The message is for people, and may change.

Framework codes​

Defined as constants on ValueObjectErrorCodes:

CodeRaised when
value_object.requiredThe value is null, or an empty string on a type without AllowEmpty.
value_object.too_shortA string is shorter than MinLength.
value_object.too_longA string is longer than MaxLength.
value_object.invalid_formatThe value does not match Pattern; also the code of ValidationResult.InvalidFormat.
value_object.out_of_rangeThe value is below Minimum or above Maximum; also the code of ValidationResult.OutOfRange.
value_object.not_a_known_valueThe value is not one of the known values of a closed set.
value_object.not_parsableThe text does not even have the shape of the underlying type, so no rule of the type ran.

Codes of your own​

A validator hook returns ValidationResult.Failure("delivery_date.sunday", "Nothing is delivered on a Sunday.") for a rule of its own. Prefer a specific code of your own over a framework code that means something else: a client can act on delivery_date.sunday, not on a generic value_object.invalid_format.

ValidationResult​

A readonly struct returned by Validate, by TryCreate and TryParse through their out parameter, and by validator hooks.

Member
static ValidationResult SuccessThe success state, which is default: accepting a value allocates nothing.
bool IsValidtrue on success.
string? ErrorCode, string? ErrorMessageThe code and message of the rule that fired, null on success.
static ValidationResult Failure(string errorCode, string errorMessage)A rejection with a code of your own.
Required, InvalidFormat, OutOfRangeRejections with the framework code and an optional message.

Validation is fail-fast: a result carries one reason, the first rule that failed.

ValueObjectException​

Thrown by Create, by Parse, and by an explicit conversion, when the value is rejected. It carries:

Member
ErrorCodeThe code of the violated rule, the same TryCreate would have reported.
ValueObjectTypeThe value object that refused the value.
AttemptedValueThe value as it was passed in, before normalization.
MessageThe message of the violated rule.

Every integration on a boundary — JSON, model binding, EF Core, Dapper — uses TryCreate instead, so the exception is reserved for code that treats a rejected value as a bug.

Detecting an uninitialized instance​

IsDefault is true for an instance that was never constructed: one that crossed a boundary the VO0010 analyzer cannot see, such as a default array element or another library's deserializer. FluentValidation's NotDefault rule checks it at the edge.