laravel/framework · error · UnexpectedValueException
User must implement CanResetPassword interface.
Error message
User must implement CanResetPassword interface.
What it means
Thrown by PasswordBroker::getUser() when the user retrieved by credentials does not implement Illuminate\Contracts\Auth\CanResetPassword. The broker needs this contract to call sendPasswordResetNotification() and to delete/store reset tokens.
Source
Thrown at src/Illuminate/Auth/Passwords/PasswordBroker.php:183
return $user;
}
/**
* Get the user for the given credentials.
*
* @param array $credentials
* @return \Illuminate\Contracts\Auth\CanResetPassword|null
*
* @throws \UnexpectedValueException
*/
public function getUser(#[\SensitiveParameter] array $credentials)
{
$credentials = Arr::except($credentials, ['token']);
$user = $this->users->retrieveByCredentials($credentials);
if ($user && ! $user instanceof CanResetPasswordContract) {
throw new UnexpectedValueException('User must implement CanResetPassword interface.');
}
return $user;
}
/**
* Create a new password reset token for the given user.
*
* @param \Illuminate\Contracts\Auth\CanResetPassword $user
* @return string
*/
public function createToken(CanResetPasswordContract $user)
{
return $this->tokens->create($user);
}
/**
* Delete password reset tokens of the given user.View on GitHub (pinned to bd6b5437e6)
Solutions
- Make the User model implement Illuminate\Contracts\Auth\CanResetPassword and use the Illuminate\Foundation\Auth\CanResetPassword trait (and Notifiable for the reset notification).
- If using a custom model, implement getEmailForPasswordReset() and sendPasswordResetNotification() manually.
- Ensure the provider's 'model' config points at the correct class implementing the contract.
- Add a static check in tests: assertTrue(is_subclass_of(User::class, CanResetPassword::class)).
Example fix
// before
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
// missing CanResetPassword trait
}
// after
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use Notifiable; // provides sendPasswordResetNotification
// Authenticatable already uses CanResetPassword trait
} Defensive patterns
Strategy: type-guard
Validate before calling
$model = config('auth.providers.users.model');
if (! is_subclass_of($model, \Illuminate\Contracts\Auth\CanResetPassword::class)) {
throw new RuntimeException("User model [{$model}] must implement CanResetPassword.");
} Type guard
function userImplementsCanResetPassword(string $modelClass): bool
{
return is_subclass_of($modelClass, \Illuminate\Contracts\Auth\CanResetPassword::class);
} Try / catch
try {
$status = Password::broker()->sendResetLink($credentials);
} catch (\UnexpectedValueException $e) {
// surface a config error: the User model is missing the contract/trait
report($e);
} Prevention
- Extend Illuminate\Foundation\Auth\User (or use the CanResetPassword + Notifiable traits) on custom models.
- Add a static assertion in tests that the User model implements CanResetPassword.
- Keep the providers.users.model config pointing at the class that implements the contract.
When it happens
Trigger: Calling Password::broker()->sendResetLink([...]) where the matched User model lacks the CanResetPassword implementation (and the CanResetPassword trait that wires getEmailForPasswordReset() and sendPasswordResetNotification()).
Common situations: A custom User model that extends a base other than Illuminate\Foundation\Auth\User; removed the Notifiable + CanResetPassword traits; switched to a non-Eloquent user provider whose model is a plain stdClass.
Related errors
- Password resetter [{$name}] is not defined.
- Auth guard [{$name}] is not defined.
- Auth driver [{$config['driver']}] for guard [{$name}] is not
- Unable to bind custom driver callback
- Authentication user provider [{$driver}] is not defined.
AI-assisted analysis of laravel/framework@bd6b5437e6 (2026-08-06).
Data as JSON: /data/errors/f1e51384f08e8a4e.json.
Report an issue: GitHub.