Repository navigation
[6.x] Fix last login errors when the app uses CarbonImmutable - #15793
Open
jhhazelaar wants to merge 1 commit into
Open
jhhazelaar wants to merge 1 commit into
jhhazelaar wants to merge 1 commit into
Conversation
Apps that call Date::use(CarbonImmutable::class) get immutable dates from now() and from datetime casts. The Eloquent user's lastLogin() then parsed the date again as a string, which fails in the Control Panel, and Passkey::setLastLogin() threw a TypeError on passkey login and when saving an Eloquent passkey.
jhhazelaar
marked this pull request as ready for review
November 5, 2026 10:18
This branch has not been deployed
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.
Apps that call
Date::use(CarbonImmutable::class)getCarbonImmutableinstances fromnow()and from Eloquent'sdatetimecasts. The Laravel starter kits do this by default. Two places in the auth code only accept a mutableCarbon\Carbon, so they break in those apps:Eloquent users: the Control Panel crashes right after logging in
When the user model casts
last_logintodatetime,Statamic\Auth\Eloquent\User::lastLogin()receives aCarbonImmutable. That fails theinstanceof Illuminate\Support\Carboncheck, so the date is cast to a string and parsed again with the model's date format (Y-m-d H:i:s). In the Control Panel, theLocalizemiddleware sets the to-string format to ISO 8601, and the parse throws:The first Control Panel page after a login renders the user's augmented data, so the error shows up as soon as
last_loginhas been filled.Passkeys: a TypeError on login and when saving an Eloquent passkey
Passkey::setLastLogin()is typednull|int|Carbon. It receives aCarbonImmutablein two places: whenWebAuthnrecords a passkey login withnow(), and whenEloquent\Passkey::setModel()passes thedatetimecast fromWebAuthnModel(which also runs aftersave()):The fix
Like #3499, #11244 and #13760, this accepts
CarbonInterface:Eloquent\User::lastLogin()returns the date as it is when it is any Carbon instance, and only parses strings.Passkey::setLastLogin()(the contract and the abstract class) acceptsnull|int|CarbonInterfaceand converts the date withCarbon::instance().lastLogin(): ?Carbonstays the same, soFile\Passkeyand any code reading the value are unaffected. One caveat: a class that implements thePasskeycontract directly (rather than extendingStatamic\Auth\WebAuthn\Passkey) and declaressetLastLogin(null|int|Carbon $time)would no longer be compatible with the contract. If you'd rather avoid that, the contract can stay as it is and only the abstract class gets widened. That works too, because an implementation may accept a wider type than its interface.The tests cover an Eloquent user whose model casts
last_loginwhile the app uses immutable dates,setLastLogin()with aCarbonImmutablefor both the file and Eloquent passkeys, and saving an Eloquent passkey with a last login. All of them fail without the fix.