Skip to main content

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.

Type
Resilience
When to Use
Input Validation, Unavailable Dependency, Resource Protection, Early Error Detection

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.