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 cryptoBy donating, you agree to our donation terms.
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.