---
title: Assemble a validation result and exception
summary: Collect one or more validation failures into a `ValidationResult` and optionally wrap it in a throwable `SaifValidationException`.
status: draft
owner: Framework.NCore maintainers
last_reviewed: 2026-10-02
library: SAIF.NetCore.Common
reference_type: package
operation_id: OP-08
trigger: A consumer populates a `ValidationResult` after running validation logic, or constructs a `SaifValidationException` to report a single failure.
---

# Assemble a validation result and exception

Collect one or more validation failures into a `ValidationResult` and optionally wrap it in a throwable `SaifValidationException`. This operation is triggered when a consumer populates a `ValidationResult` after running validation logic, or constructs a `SaifValidationException` to report a single failure.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-08 |
| **Trigger** | A consumer populates a `ValidationResult` after running validation logic, or constructs a `SaifValidationException` to report a single failure. |
| **Inputs** | `PropertyName`, `ErrorMessage`, `AttemptedValue` (for `ValidationFailure`); or `propertyName`/`errorMessage` (for `SaifValidationException`) |
| **Outputs** | A `ValidationResult` with populated `Errors`/`Messages`, or a `SaifValidationException` carrying a `ValidationResult`. |
| **Primary components** | `ValidationResult`, `ValidationFailure`, `SaifValidationException` |
| **Entry point** | `src/SAIF.NetCore.Common/SAIF.NetCore.Common/SAIF.NetCore.Common/Types/ValidationResult.cs` |

## Steps

1. Consumers add `ValidationFailure` entries (`PropertyName`, `ErrorMessage`, `AttemptedValue`) to `ValidationResult.Errors`, and informational strings to `Messages`.
2. Read `ValidationResult.IsValid`, which is `true` only when `Errors` contains no entries. ([BR-020](../business-rules.md#br-020-a-validation-result-is-valid-only-when-it-has-no-errors))
3. Construct `SaifValidationException` either directly from a `ValidationResult`, or via the `(propertyName, errorMessage)` / `(errorMessage)` constructors, which build a `ValidationResult` containing exactly one failure.
   - No constructor sets `Exception.Message`, so the base `Exception.Message` default is used even though a `ValidationResult` with failure text is attached.

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
	Start([Validation logic runs]) --> AddFailures["Add ValidationFailure entries<br>to Errors / Messages"]
	AddFailures --> CheckValid{Errors empty?}
	CheckValid -->|Yes| Valid(["IsValid = true"])
	CheckValid -->|No| Invalid(["IsValid = false"])
	Invalid --> Construct["Construct SaifValidationException<br>from ValidationResult"]
	Construct --> End([Throw to caller])
```

## Failure and edge-case behavior

- `Messages` entries never affect `IsValid`; only `Errors` does.
- `SaifValidationException` never sets its own `Exception.Message`, so callers must inspect `ValidationResult` rather than `.Message` for failure detail.

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)

## Sources
- `src/SAIF.NetCore.Common/SAIF.NetCore.Common/SAIF.NetCore.Common/Types/ValidationResult.cs`
- `src/SAIF.NetCore.Common/SAIF.NetCore.Common/SAIF.NetCore.Common/Types/ValidationFailure.cs`
- `src/SAIF.NetCore.Common/SAIF.NetCore.Common/SAIF.NetCore.Common/Types/SaifValidationException.cs`
