fix(core): keep the cause of a load or verification failure - #699
Merged
Conversation
The loaders, the verifier, the decrypter and the serializer managers all swallowed the exception explaining why a token could not be used, and the caller was left with a bare "Unable to load and verify the token." with no previous exception. The last error met along the way is now chained as the previous exception. The per-key failures of JWSVerifier and JWEDecrypter, which cannot throw without changing the return semantics, are reported through a callable accepted as an additional argument; it will become part of the signature in 5.0.0. Closes #681
Spomky
force-pushed
the
fix/loader-exception-chaining
branch
from
August 28, 2026 12:30
8b7db79 to
7e93ca0
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #681.
When loading a token failed, every layer swallowed the exception explaining why, and the caller ended up with a bare
Unable to load and verify the token.and noprevious. Whatever the real reason was — malformed token, unsupportedalg, rejected header, unusable key — the message was the same.The last error met along the way is now chained as the previous exception. No BC break: the exception classes and the messages are unchanged, only
getPrevious()is populated.Changes
JWSSerializerManager,JWESerializerManagerUnsupported input.now chains the lastInvalidArgumentExceptionthrown by a serializerJWSLoader,JWELoader$previousJWSVerifier,JWEDecrypterThrowables that are discarded to try the next key are reported to the callerJWSVerifier::verifyWithKeySet()andJWEDecrypter::decryptUsingKeySet()return abooland cannot throw without changing their semantics, and adding a parameter would break classes extending them. The callable that observes those failures is therefore passed as an undeclared additional argument and read withfunc_num_args()/func_get_arg(5)— the same pattern already used byJWEDecrypter::decryptCEK(). It will become part of the signature in 5.0.0. A subclass that overrides the method simply ignores it and behaves exactly as today.Result
One case still has no
previous, by design: rightkty, rightalg, signature that does not match. NoThrowableis thrown there —verify()simply returnsfalse.The dedicated exception hierarchy (so that
catch (JoseException)becomes possible) remains the separate 4.3.0 issue.Checks