# Ardalis.GuardClauses: fail-fast validation for .NET constructors and methods

> A NuGet package that turns repeated null and range checks into one-line guard clauses. It is small, MIT licensed, and extensible, but it is not a validation framework and it does not replace FluentValidation.

**ardalis/GuardClauses** — A simple package with guard clause extensions.

- Repository: https://github.com/ardalis/GuardClauses
- Stars: 3,314 · Forks: 295
- Language: C#
- License: MIT
- Published: 2026-09-24 · Updated: 2026-09-24 · Language: en
- Canonical page: https://hysenlabs.com/projects/ardalis-guardclauses

## What problem Ardalis.GuardClauses solves, and for whom

The README describes a guard clause as a pattern that simplifies complex functions by failing fast: checking invalid inputs up front and failing immediately when one is found. In practice, that means the top of a constructor or method fills with repeated null checks, empty string checks and range checks before any real work starts. Ardalis.GuardClauses packages those checks as extension methods on a Guard.Against entry point so each one is a single line.

The audience is .NET developers, particularly those writing domain models and services where an object should never exist in an invalid state. The package's topics list clean-architecture, clean-code and design-patterns, which matches the style of code the README demonstrates: an Order constructor that assigns fields only after each value has been checked. If your codebase already has a house style for argument checks, this package mostly changes how those checks read, not what they do.

## How the guard methods are structured and extended

The mechanism is a static entry point plus extension methods. Guard.Against is the surface you call, and each supported clause is an extension method that inspects the input and throws when the input is invalid. The README lists the supported clauses: Null, NullOrEmpty for strings, guids and arrays, NullOrWhiteSpace, OutOfRange for integers, DateTime values and enums, EnumOutOfRange, OutOfSQLDateRange, Zero, Expression, InvalidFormat and NotFound. NotFound is the odd one out: it throws a NotFoundException rather than an argument exception, which fits id or key lookups rather than constructor arguments.

Extension is the part worth understanding before adopting. The README shows a FooGuard class placed in the Ardalis.GuardClauses namespace so your code picks up your extensions no matter where they sit in the codebase. The extension method takes the IGuardClause instance as its first parameter and uses CallerArgumentExpression to capture the parameter name automatically, with an optional explicit nameof argument if you prefer. That means a custom guard gets the same call shape as the built-in ones, and the parameter name in the thrown exception comes from the call site rather than from a string you maintain by hand.

## Installing Ardalis.GuardClauses and writing a first guard

The package is published on NuGet as Ardalis.GuardClauses. The README shows the NuGet badge pointing at that package id, and the repository keeps the project under src/ with a GuardClauses.sln at the root. The README's first example is a method that rejects a null argument before doing anything else:

```c#
public void ProcessOrder(Order order)
{
    Guard.Against.Null(order);

    // process order here
}
```

Calling ProcessOrder(null) throws immediately rather than letting a null reference surface later. The README's second example shows guards inside a constructor, where each parameter is checked and the result assigned to a field:

```c#
public Order(string name, int quantity, long max, decimal unitPrice, DateTime dateCreated)
{
    _name = Guard.Against.NullOrWhiteSpace(name);
    _quantity = Guard.Against.NegativeOrZero(quantity);
    _max = Guard.Against.Zero(max);
    _unitPrice = Guard.Against.Negative(unitPrice);
    _dateCreated = Guard.Against.OutOfSQLDateRange(dateCreated, dateCreated);
}
```

Note the call shape: the guard returns the checked value, so it can be assigned directly. The OutOfSQLDateRange call passes the value twice, which is how the README writes it. If you supply an invalid quantity, the constructor throws before the object is constructed, so no partially initialized Order escapes. The README does not give a CLI install command; it points to the package page on nuget.org, so install it through your usual NuGet client or the package manager UI of your IDE.

## Where the guard clause approach stops being the right tool

A guard clause is an argument check, not a validation framework. The README's list covers null, empty, whitespace, range, enum range, SQL date range, zero, format and not-found cases. Anything that depends on more than the argument itself, such as two fields that must agree, a rule that needs a database lookup, or a message that must be localized, falls outside that list and needs Guard.Against.Expression or a custom guard, or a different library altogether.

There is also a versioning cost. The README documents breaking changes in v4: OutOfRange for enums now uses EnumOutOfRange, and custom error messages now work more consistently, which the README warns may break some unit tests. If your tests assert on exception messages, upgrading across that boundary is not a drop-in change. The same README section is the reason to read release notes before bumping the package rather than after.

Finally, the repository's build notes are written for maintainers and describe a publishing step that can report success while the package is not actually published: a GitHub release with a form like 1.3.2 is required for the package to reach NuGet. That is an internal detail, but it is a reminder that the project's release process has manual steps, and the release history shows v5.0 in September 2024 followed by v4.6.0 and v4.5 earlier that year.

## Ardalis.GuardClauses compared with FluentValidation

FluentValidation takes a different approach: you define a validator class that describes rules for a model and run it against an instance, which lets rules depend on other properties and lets you collect all failures at once. Ardalis.GuardClauses does the opposite. Each guard checks one argument at the point of entry and throws on the first failure, so you get fail-fast behavior rather than a collection of validation results.

That difference decides the choice. If you want to return a list of field errors to an API client, a validator that accumulates failures fits better. If you want a constructor to refuse invalid input so an object cannot exist in a bad state, a guard clause fits better. The two can coexist: guards at the boundary of your domain types, validators at the boundary of your HTTP requests. The README does not present the package as a replacement for a validation framework, and treating it as one is a common way to end up with guards scattered through code that should have been a single validator.

## Maintenance, licensing and upgrade cost

The repository is not archived, and the last push was on 2026-09-16, which is recent relative to the release history. The latest release listed is v5.0 from 2024-09-30, so the code has moved since the last tagged release. The README directs commercial support enquiries to NimblePros, which is the clearest signal that the project has an owner with a commercial interest in it.

The licence is MIT, which permits use in closed-source and commercial applications. That is a permissive licence, and the practical implication is that you can ship the package inside a proprietary product without publishing your own source. This is not legal advice; read the LICENSE file in the repository if your organisation has specific requirements.

Upgrade cost is mostly the v4 breaking changes described above. If you are already on v4 or later, the README does not document further breaking changes for v5.0, so the main thing to verify is whether your tests assert on exception messages. The README also keeps a YouTube overview and a set of external references, which are useful when you need to explain the pattern to a team that has not used it.

## Conclusion

Adopt Ardalis.GuardClauses if you write C# constructors and public methods that must reject bad arguments before doing work, and you want those checks to read as one line each. Skip it if your validation rules depend on runtime data, cross-field business rules or localized messages that belong in a validation framework such as FluentValidation. Before adding it, check the v5.0 release notes against your current version, because the README documents breaking changes in v4 around EnumOutOfRange and custom error messages.

## FAQ

### What are guard clauses in C#?

A guard clause is a pattern that checks for invalid inputs up front and fails immediately when one is found, which the README describes as failing fast. In C#, that usually means an argument check at the top of a method or constructor, such as Guard.Against.Null(order) before the rest of the method runs.

### What guard clauses does Ardalis.GuardClauses support?

The README lists Null, NullOrEmpty, NullOrWhiteSpace, OutOfRange, EnumOutOfRange, OutOfSQLDateRange, Zero, Expression, InvalidFormat and NotFound. NotFound differs from the others because it throws a NotFoundException, which suits id or key lookups rather than constructor arguments.

### How do I install Ardalis.GuardClauses?

The package id is Ardalis.GuardClauses, and the README links to it on nuget.org. The README does not give a CLI install command, so install it through your usual NuGet client or your IDE's package manager using that id.

### Can I write my own guard clause with Ardalis.GuardClauses?

Yes. The README shows a static class placed in the Ardalis.GuardClauses namespace with an extension method whose first parameter is IGuardClause, using CallerArgumentExpression to capture the parameter name. The README notes that using the same namespace makes your code pick up the extensions wherever they are in your codebase.

### Does Ardalis.GuardClauses replace FluentValidation?

No. Ardalis.GuardClauses checks individual arguments at the point of entry and throws on the first failure, while a validation framework accumulates rule failures for a model. The README presents the package as a set of guard clause extensions, not as a validation framework.

## Sources

- [ardalis/GuardClauses on GitHub](https://github.com/ardalis/GuardClauses)
- [Issues](https://github.com/ardalis/GuardClauses/issues)
- [License: MIT](https://github.com/ardalis/GuardClauses/blob/main/LICENSE)
- [README](https://github.com/ardalis/GuardClauses/blob/main/README.md)
- [Releases](https://github.com/ardalis/GuardClauses/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/ardalis-guardclauses
