lynndylanhurley/devise_token_auth · error · ActionController::RoutingError
Not Found
Error message
Not Found
What it means
Raised by the GET /auth/unlock endpoint (UnlocksController#show, the landing action for account-unlock emails; render_show_error at unlocks_controller.rb:79). It applies when Devise lockable runs with an email unlock strategy. The action calls unlock_access_by_token; when no persisted user matches the unlock_token (blank, unknown, or already consumed because unlocking clears the stored token), render_show_error raises ActionController::RoutingError and Rails returns 404, deliberately hiding whether the account exists.
Source
Thrown at app/controllers/devise_token_auth/unlocks_controller.rb:79
render_error(401, I18n.t('devise_token_auth.unlocks.missing_email'))
end
def render_create_success
render json: {
success: true,
message: success_message('unlocks', @email)
}
end
def render_create_error(errors)
render json: {
success: false,
errors: errors
}, status: 400
end
def render_show_error
raise ActionController::RoutingError, 'Not Found'
end
def render_not_found_error
if Devise.paranoid
render_create_success
else
render_error(404, I18n.t('devise_token_auth.unlocks.user_not_found', email: @email))
end
end
def resource_params
params.permit(:email, :unlock_token, :config)
end
end
end
View on GitHub (pinned to b02076a930)
Solutions
- If the account is still locked, request a new unlock email via POST /auth/unlock with the account email and use the newest link
- Verify the model declares devise :lockable with an unlock_strategy that includes :email and that the users table has the lockable columns (failed_attempts, unlock_token, locked_at) via the Devise lockable migration
- Compare the token in the link against User.find_by(email: ...).unlock_token in the console to catch truncation or escaping
- Unblock the user immediately from the console with user.unlock_access! or wait for the lock to lapse per Devise.unlock_in
- For API-only apps, override DeviseTokenAuth::UnlocksController#render_show_error to render JSON instead of raising RoutingError
Example fix
# before - devise_token_auth default
def render_show_error
raise ActionController::RoutingError, 'Not Found'
end
# after - app/controllers/unlocks_controller.rb (host app override)
class UnlocksController < DeviseTokenAuth::UnlocksController
def render_show_error
render json: { success: false, errors: ['Invalid or already used unlock token.'] }, status: :not_found
end
end
# config/routes.rb
mount_devise_token_auth_for 'User', at: 'auth', controllers: { unlocks: 'unlocks' } Defensive patterns
Strategy: fallback
Validate before calling
// before sending the user to the unlock landing page
function assertUnlockLinkParams(query) {
if (!query.get('unlock_token')) throw new Error('unlock_token missing from link');
return query;
} Type guard
const isPlausibleUnlockToken = (t) =>
typeof t === 'string' && /^[A-Za-z0-9_-]{10,}$/.test(t); Try / catch
// client handling of the unlock landing request
const res = await fetch(unlockUrl, { redirect: 'manual' });
if (res.status === 404) {
// token unknown or already used: fall back to requesting a fresh unlock email
await requestUnlockEmail(email);
} Prevention
- Treat unlock links as single-use and always start from the newest unlock email
- Confirm lockable is actually configured (devise :lockable, unlock_strategy including :email, lockable migration run) before shipping unlock emails
- When admins unlock accounts manually, expect the outstanding email link to 404
- Monitor 404 rates on /auth/unlock to catch broken email templates early
When it happens
Trigger: GET /auth/unlock?unlock_token=X where X is missing, matches no user row, was already used on an earlier visit (the token is cleared once the account is unlocked), or comes from an older unlock email after the account relocked and generated a newer token.
Common situations: Models missing devise :lockable or an unlock_strategy that includes :email, so no valid unlock tokens ever exist (or the lockable migration with unlock_token was never run); users clicking the unlock link twice (first click succeeds, second 404s); admins manually unlocking accounts while users later open the stale email; mail clients mangling the token in the link.
Related errors
AI-assisted analysis of lynndylanhurley/devise_token_auth@b02076a930 (2026-08-23).
Data as JSON: /api/errors/8991a0e25f9ae86b.
Report an issue: GitHub.