Fail Fast
Fail Fast detects invalid input, missing configuration, or dead dependencies at the earliest point and reports the error immediately instead of failing deeper and costlier. It applies to recoverable failures with care, and contrasts with the fail-safe approach.
When something is clearly wrong, the worst response is to plod onward and fail later, after consuming resources and obscuring the root cause. The Fail Fast principle says: detect problems at the earliest possible point and surface the error immediately. A request with invalid input, a missing required configuration, or a known-dead dependency should be rejected up front, not deep inside a transaction.
How It Works
Fail-fast pushes checks to the front of an operation and treats violations as immediate, explicit failures:
- Input validation at the boundary: reject malformed requests before any work begins.
- Precondition and invariant checks: assert assumptions early (non-null arguments, valid ranges, required state) and throw on violation.
- Startup/configuration validation: refuse to start if required settings are missing, so the failure happens at deploy time, not in production traffic.
- Short-circuiting on known failure: an open circuit breaker fails fast instead of attempting a doomed call; a full queue rejects immediately instead of enqueuing.
The goal is a short path from "something is wrong" to "caller knows," with a clear, actionable error.
When to Use It
Use fail-fast for input validation, for verifying preconditions in critical operations, and for configuration checks at startup. It pairs with circuit breakers and load shedding, where the resilient choice under known failure is to reject quickly. It is the right default for internal correctness: a violated invariant should crash loudly in development rather than corrupt data silently.
Trade-offs
Fail-fast can reduce availability if applied bluntly to recoverable conditions — failing immediately on a transient blip forgoes the chance to retry. The art is distinguishing unrecoverable errors (fail fast) from transient ones (retry, fall back). It also tightens coupling to validation rules, which must stay accurate. For user-facing systems, raw fast failures may need wrapping in friendlier messages or fallbacks.
Related Patterns
Fail-fast complements circuit-breaker (fast-fails calls to a broken dependency), timeout-pattern (bounds waiting so failure surfaces promptly), and load-shedding. It contrasts with fail-safe, which prioritizes continuing in a safe default state over halting.
Example
Validating at the boundary:
func Transfer(req TransferRequest) error {
if req.Amount <= 0 { return ErrInvalidAmount } // fail fast
if req.From == req.To { return ErrSameAccount } // fail fast
return ledger.Apply(req) // only valid work proceeds
}
The expensive ledger operation runs only after cheap checks pass, and the caller gets a precise error immediately.