Skip to content

Errors & exceptions

Warrant fails loudly. A typo in a stored rule, a missing context key, or a misconfigured schema throws rather than silently granting or denying. This is the catalogue.

Stage What’s checked
Parse time Rule syntax, binding consistency (WarrantSyntaxException)
Compile / validate time Ability / condition / context-key names exist on the schema
Check time Requested ability exists; required context present; user available
Boot / reflection Schema registry uniqueness; condition method signatures

Thrown eagerly from the lexer/parser. Extends RuntimeException and carries $source, $offset, $sourceLine, and $sourceColumn. The message includes the line, column, and a caret:

Reserved word 'can' cannot be used as a name; expected an ability name. (line 1, column 21)
if is_self they can can
^

Representative messages:

  • Unexpected character %s.
  • Unterminated string literal.
  • Invalid escape sequence "\%s"; only \' and \\ are allowed.
  • Expected 'context' after '@'. / Expected a context key after '@context'.
  • Expected 'can' or 'cannot' after 'they'.
  • Expected at least one 'they can ...' or 'they cannot ...' clause.
  • Expected ')' to close the group. / Expected ')' to close the condition arguments.
  • Reserved word '%s' cannot be used as a name; expected %s.
  • Expected a rule. / Expected a single rule but found multiple.

Binding errors (also WarrantSyntaxException)

Section titled “Binding errors (also WarrantSyntaxException)”
  • Cannot mix named and positional bindings.
  • No binding provided for ":%s".
  • More positional placeholders (?) than bindings provided.
  • %d positional binding(s) were provided but never used.
  • Binding(s) provided but never used: %s.

Validation errors → InvalidArgumentException

Section titled “Validation errors → InvalidArgumentException”

Thrown when a rule set is validated/compiled against a schema:

  • Ability [%s] is not declared by the schema.
  • Condition [%s] is not declared by the schema.
  • Context key [%s] is not declared by the schema.

Attaching a denial message to a rule that has no theyCannot clause is also rejected here — only a cannot rule may carry a withDenialMessage(). See Denial messages.

fromRules / validateAll type-guard their inputs:

  • fromRules expects WarrantRule or WarrantRuleBuilder instances, got %s.
  • validateAll expects WarrantRuleSet instances, got %s.

Condition / reflection errors → InvalidArgumentException

Section titled “Condition / reflection errors → InvalidArgumentException”

Thrown lazily the first time a schema’s conditions are reflected:

  • Condition method [%s::%s] must not declare duplicate condition attributes.
  • Condition method [%s::%s] cannot declare both #[TargetedCondition] and #[GlobalCondition].
  • Condition method [%s::%s] must resolve to a non-empty condition key.
  • Condition method [%s::%s] must accept exactly one [%s] parameter. — wrong context type or an extra parameter.
  • Schema [%s] is a schema with no model and does not support targeted checks; use a no-target check instead.

From the condition resolver:

  • BadMethodCallExceptionCondition [%s] is not defined on schema [%s].
  • InvalidArgumentExceptionCondition [%s] on schema [%s] requires a target SQL id. (a targeted condition run with no target)

Context errors → InvalidArgumentException

Section titled “Context errors → InvalidArgumentException”
Schema [%s] requires context key(s) [%s]; supply them at the check or via defaultContext().

See Check-time context. Note the fail-open caveat: an optional key that’s absent doesn’t throw — it soft-falses its condition.

  • InvalidArgumentExceptionDuplicate schema for schema key ... / Duplicate schema for model ... (at boot)
  • OutOfBoundsExceptionNo Warrant schema registered for model [%s].
  • OutOfBoundsExceptionNo Warrant schema registered for schema key [%s].

Authorization failures → WarrantAuthorizationException

Section titled “Authorization failures → WarrantAuthorizationException”

Thrown by authorize() when a check is denied. It extends Illuminate\Auth\Access\AuthorizationException, so Laravel renders it as HTTP 403 automatically.

public function __construct(
string $message = 'This action is unauthorized.',
?WarrantDenialContext $denial = null,
);
public readonly ?WarrantDenialContext $denial; // the diagnosed denial, or null for a generic denial

The $denial property carries a diagnosed denial-context data object (a plain final readonly object under Warrant\, not an exception) describing why the check failed:

  • WarrantGate — the requested array $abilities (normalized, wildcards resolved) and AbilityMatchMode $matchMode.
  • WarrantDenialContext$user, ?Model $target, string $schema, array $context, WarrantGate $gate, the responsible WarrantRule $rule (the matching cannot), and array $deniedAbilities.
  • WarrantUngrantedContext — same fields minus $rule, with array $ungrantedAbilities in place of deniedAbilities (the whole gate under ANY; the missing subset under ALL).

See Denial messages for attaching messages and the schema fallback hooks.

See Middleware API. Unauthenticated or unauthorized requests abort(403); misconfiguration throws InvalidArgumentException.

  • ... requires an authenticated user or an explicit user instance. (scopes/helpers with no user)
  • Model [%s] must return a WarrantSchema class string, got [%s].
  • Schema [%s] must manage model [%s], got [%s].

Thrown by toSyntax() when a rule can’t be rendered as inline DSL — use toBoundSyntax() instead:

  • A constant boolean expression has no rule-language representation.
  • Condition parameter of type %s cannot be written inline; use toBoundSyntax().
  • NAN/INF cannot be written inline; use toBoundSyntax().
  • Float %s requires exponent notation, unsupported inline; use toBoundSyntax().

Configuration & driver errors → RuntimeException

Section titled “Configuration & driver errors → RuntimeException”
  • No Warrant rule resolver configured. Set warrant.rule_resolver to a class implementing Warrant\RuleResolver.
  • Warrant ability selection does not support the [%s] database driver. (a driver other than PostgreSQL, MySQL/MariaDB, or SQLite for the per-row abilities column)