---
title: "Exceptions, statuses and enums — Sentinel for Laravel | Roundly"
description: "Every exception and when it is thrown, the HTTP problem responses, verification status values and every enum Sentinel ships."
url: https://roundly-consulting.com/open-source/docs/sentinel-for-laravel/exceptions
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Sentinel for Laravel](https://roundly-consulting.com/open-source/docs/sentinel-for-laravel.md)

# Exceptions, statuses and enums

Every exception extends RoundlyConsulting\\Sentinel\\Exceptions\\SentinelException (a RuntimeException), except the HTTP-facing ones, which extend Symfony’s HttpException and render RFC 9457 problem details. Messages are developer-facing English (HTTP messages are translated) and never contain key material or sealed values.

| Exception | When |
| --- | --- |
| `InvalidSealDefinitionException` | A seal definition does not compile — problems() lists every problem. |
| `SealingMisconfiguredException` | Wiring errors, fail closed: notSealable, unknownSeal (lists the declared seals), unknownRing, notAMacRing (a MAC call on a ring that seals, the ledger or HTTP signatures use), saveOverridden, writeOutsideSealedPath, keyChanged (a save that changes a sealed row’s primary key), middlewareParameter, bindingsNotSubstituted, queryModelMismatch, missingColumn, unknownModel, invalidColumn, middlewareOption, whereNeedsOneModel. |
| `CanonicalizationException` | A value cannot be canonicalized — field() and reason() name the field and rule, never the value. |
| `NoSigningKeyException` | No active key with private material in the ring; the message names the ring’s key variables and, in testing, points at WithSentinelKeys or Sentinel::fake(). |
| `UnknownKeyException` | A kid unknown in that ring (also a kid of another ring). |
| `MacVerificationException` | verifyMac() refused a MAC — reason() gives the MacRejection, ring() and keyId() the ring and the kid as passed (escape the kid before rendering it); never contains the MAC, the message or key material. |
| `KeyIntegrityException` | A database key row disagrees with its envelope. |
| `InvalidKeyMaterialException` | Key material refused (encoding, length, weak secret, curve mismatch, private material on a verify-only import, …). |
| `AlgorithmNotAllowedException` | An algorithm outside an allow-list — notHmac when mac() meets an Ed25519 or ECDSA signing key. |
| `KeyDriverException` | Key lifecycle refusals: readOnly, customDriver (rotating a ring that signs with a custom driver’s key), ringBusy (MySQL/MariaDB: another rotation of the ring held its lock past innodb\_lock\_wait\_timeout), notStoredInDatabase, keyIdTaken, reasonRequired, invalidKeyId, invalidLabel. |
| `ConcurrentSealException` | A lost race (the write rolls back). |
| `SealingFailedException` | Sealing or verifying an unsaved model (notPersisted — seal(), verify(), verifyAll(), isIntact()) / a row gone during sealing. |
| `TamperedModelException` | verifyOrFail(), a refused write, a refused mass update — result() / results(). |
| `SealingSuspensionNotAllowedException` | withoutSealing() with allow\_suspension off. |
| `AcknowledgementDeniedException` | Acknowledgement / unseal / baseline refused: reason, reasonTooLong, actorRequired, unauthorized. |
| `LedgerIsAppendOnlyException` | An Eloquent update or delete of a ledger entry or checkpoint. |
| `LedgerIntegrityException` | LedgerReport::throwIfViolated() — findings() returns the violations. |
| `AnchorPublishException` | An anchor refused a checkpoint (diverged — it holds one the database no longer agrees with) or its store reported a failed write (notWritten); the checkpoint run catches it and reports AnchorPublishFailed. |
| `InvalidSentinelConfigurationException` | Invalid configuration, thrown at first use and never replaced by a default — the message names the key (for a boolean, also the value given). |
| `InvalidPurposeException` | A nonce purpose outside the alphabet. |
| `IdempotentResultException` | idempotency()->run() returned something not storable as JSON — the callback ran, its key is completed as unreplayable. |

## HTTP exceptions

| Exception | Status | code |
| --- | --- | --- |
| `Http\Exceptions\SealVerificationFailedHttpException` | middleware.verified\_status (409) | — (generic message) |
| `IdempotencyKeyMissingException` | 400 | `idempotency_key_missing` |
| `InvalidIdempotencyKeyException` | 400 | `invalid_idempotency_key` |
| `IdempotencyKeyReusedException` | 422 | `idempotency_key_reused` |
| `IdempotencyRequestInProgressException` | 409 + Retry-After | `idempotency_request_in_progress` |
| `IdempotentResponseUnavailableException` | 409 | `idempotent_response_unavailable` |
| `NonceRejectedException` | 403 | `nonce_rejected` |
| `HttpSignatureException` | 401 (+ Accept-Signature) | `signature_rejected` |

Problem bodies carry type (when configured), title, status, detail and code, with Content-Type: application/problem+json; type is problems.type\_base#code, and title and detail are translated. The idempotency family shares the abstract IdempotencyException — rejection() returns the IdempotencyRejection, retryAfterSeconds() the Retry-After value — and HttpSignatureException has reason() and keyId().

## Verification statuses

VerificationStatus values are frozen; case names are the studly forms of the values. isIntact() and isFailure() apply the same rule as VerificationResult::isIntact(), and translated labels ship in sentinel::statuses:

| Case | Value | Intact? |
| --- | --- | --- |
| `Intact` | `intact` | yes |
| `Outdated` | `outdated` | yes, unless verification.outdated\_is\_intact is off |
| `Unsealed` | `unsealed` | yes (lenient seals) |
| `Tampered` | `tampered` | no |
| `Missing` | `missing` | no |
| `Stale` | `stale` | no |
| `UnknownKey` | `unknown_key` | no |
| `RevokedKey` | `revoked_key` | no |
| `RetiredKey` | `retired_key` | no |
| `AlgorithmNotAllowed` | `algorithm_not_allowed` | no |
| `AlgorithmMismatch` | `algorithm_mismatch` | no |
| `Malformed` | `malformed` | no |
| `Unverifiable` | `unverifiable` | no |

Reasons: mac, computed, canonicalization, ledger\_entry (tampered); seal\_deleted, never\_sealed, unsealed (missing); newer\_version, not\_in\_ledger, ledger\_mismatch, entity\_recreated (stale); ring\_not\_accepted, not\_found, pending, integrity (unknown key); missing\_attribute, missing\_computed, error (unverifiable).

## Enums

All live in RoundlyConsulting\\Sentinel\\Enums, are frozen, and use the enums-for-laravel helpers (values(), names(), labels(), options(), fromName(), tryFromName(), label(), is(), isIn(), …). Changing a value is a major release:

| Enum | Cases | Helpers |
| --- | --- | --- |
| `Algorithm` | `HmacSha256, HmacSha384, HmacSha512, Ed25519, EcdsaP256Sha256, EcdsaP384Sha384` | `isHmac(), isAsymmetric(), isHttpRegistered(), hashName(), hashLength(), hashAlgorithm(), cryptoAlgorithm()` |
| `KeyStatus` | `Pending, Active, VerifyOnly, Retired, Revoked` | `canSign(), canVerify()` |
| `KeyDestination` | `Config, Database` | — |
| `SealEvent` | `Sealed, Resealed, Acknowledged, Baseline, Rotated, Deleted, Unsealed` | `isTombstone()` |
| `VerificationContext` | `Api, Middleware, Retrieve, Command, Rule, Collection, Write` | — |
| `Reaction` | `Throw, Report` | — |
| `TamperedWritePolicy` | `Refuse, Reseal, Skip` | — |
| `LedgerFindingKind` | `CheckpointGap, CheckpointInvalid, CheckpointMismatch, ChainBroken, AnchorAhead, AnchorMismatch, AnchorInvalid, AnchorUnreachable, EntryInvalid, OrphanEntry, EntityDeleted, SealRolledBack, SealMissing, Backlog` | `isViolation()` |
| `IdempotencyRejection` | `Missing, Invalid, Reused, InProgress, Unavailable` | `status()` |
| `IdempotencyOutcome` | `Proceed, Replay, InProgress, Reused, Unavailable` | — |
| `SignatureRejection` | `Missing, Malformed, Ambiguous, MissingParameter, MissingComponent, UnsupportedComponent, UnsupportedAlgorithm, UnknownKey, RevokedKey, AlgorithmMismatch, AlgorithmNotAllowed, TagMismatch, NotYetValid, TooOld, Expired, DigestMismatch, UnsupportedDigest, InvalidSignature, Replayed` | — |
| `MacRejection` | `UnknownKey, PendingKey, RetiredKey, RevokedKey, UnsupportedAlgorithm, AlgorithmNotAllowed, Malformed, Mismatch` | — |
| `DigestAlgorithm` | `Sha256, Sha512` | `hashAlgorithm()` |
| `HealthStatus` | `Ok, Warning, Failure` | — |
| `NonceKind` | `Issued, Seen` | — |
| `PersistOperation` | `Save, Delete, Increment` | — |
| `TypeKind` | `Auto, String, Integer, Decimal, Float, Boolean, DateTime, Date, Json, Binary, Null, Plaintext` | `hasScale(), isDeclarable()` |

## Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

[More ways to support, including crypto](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/sentinel-for-laravel.md)
