Skip to content

q.Require

Runtime precondition — bubble an error to the enclosing function's error return when cond is false. Statement-only.

Signature

func Require(cond bool, msg ...string)

The message is optional. The bubbled error always carries the call-site file:line prefix; if a message is supplied it is appended after a : separator. Format-string needs are up to the caller (use fmt.Sprintf or string concatenation).

What q.Require does

q.Require(len(buf) >= 16, "header too short")

rewrites to (say, codec.go line 88, in a function returning error):

if !(len(buf) >= 16) {
    return fmt.Errorf("codec.go:88: %s: %w", "header too short", q.ErrRequireFailed)
}

The bubbled error reads codec.go:88: header too short: q.Require failed, and errors.Is(err, q.ErrRequireFailed) returns true (the sentinel is wrapped via %w).

In a function returning (T, error):

if !(len(buf) >= 16) {
    return *new(T), fmt.Errorf("codec.go:88: %s: %w", "header too short", q.ErrRequireFailed)
}

Without a message:

q.Require(len(buf) >= 16)
// → if !(len(buf) >= 16) { return …, fmt.Errorf("codec.go:88: %w", q.ErrRequireFailed) }
// reads as: "codec.go:88: q.Require failed"

Sentinel identity

err := encode(badBuf)
if errors.Is(err, q.ErrRequireFailed) {
    // came from a q.Require call somewhere down the stack
}

q.ErrRequireFailed is the sentinel every q.Require bubble wraps via %w. The wrapping fmt.Errorf prefixes the file:line and any user-supplied message before the sentinel, so err.Error() carries the location and errors.Is carries the identity.

Why a bubble, not a panic

q's purpose is to make error-returning code flat — not to spawn panics through the call graph. A failed precondition is just another way the call cannot succeed, so it propagates the same way every other failure does. That keeps the calling code's if err != nil (or q.Try(...)) path uniform: the caller doesn't need a defer recover() to find out a precondition didn't hold.

If you genuinely want to crash on a violated invariant — "this branch is unreachable" or "we got somewhere we shouldn't" — use q.Unreachable or q.TODO. Those exist precisely for the cases where panicking is the correct response.

When to use

  • Runtime preconditions on user-facing inputs (length, range, non-empty, etc.).
  • Defensive checks at API boundaries where the caller's contract should be enforced before downstream work begins.
  • Cheap invariant checks that catch a class of bug at the closest possible point to where it manifests.

For unit-test-style assertions inside test code, use the standard testing helpers — q.Require is for production paths.

Statement forms

Stmt-only. The enclosing function must have at least one return slot (the last must be error); the bubble has nowhere to go otherwise.

Not yet supported

  • A chain variant q.RequireE(cond).Wrap(…) / .Err(…) / .ErrF(…) for shaping the bubbled error. The current bare form constructs the error from a literal+message; if you need a sentinel or wrapped error, write the conditional explicitly today and file a request.
  • Build-tag compile-out (-tags=qrelease to strip all Requires) is tracked but not shipped. Current version always emits the check.

See also

  • q.Unreachable — panic for invariants that should be unreachable.
  • q.TODO — panic for unfinished branches you want to find at runtime.
  • q.Check — bubble on an error-only call (db.Ping, validate(x)).