instructure/canvas-lms · error · AccessTokenError
masquerading user not found
Error message
masquerading user not found
What it means
When an InstAccessToken declares a masquerading (real) user via masquerading_user_uuid/shard_id, the token handler resolves that user on the specified shard. If no user with that UUID exists on that shard, AccessTokenError 'masquerading user not found' is raised and the request is rejected.
Solutions
- Re-mint the InstAccess token after the masquerading user's data changes or deletion
- Verify masquerading_user_shard_id matches the shard where the user's UUID is stored
- Check find_user_by_uuid_prefer_local resolution and confirm the user record exists in the Rails console
- Reject/refresh stale tokens instead of replaying long-lived ones
Example fix
// before real_user = find_user_by_uuid_prefer_local(token.masquerading_user_uuid) // after real_user = find_user_by_uuid_prefer_local(token.masquerading_user_uuid) raise AccessTokenError, "masquerading user not found" unless real_user // add caller-side rescue rescue AccessTokenError => e render error and force token refresh
Defensive patterns
Strategy: try-catch
Validate before calling
if token.masquerading_user_uuid user = User.where(uuid: token.masquerading_user_uuid).shard(token.masquerading_user_shard_id).exists? raise "stale token" unless user end
Try / catch
begin
auth_context = InstAccessToken.authenticate!(token)
rescue AccessTokenError => e
render json: { error: e.message }, status: :unauthorized
end Prevention
- Keep token lifetimes short for masqueraded access
- Refresh tokens when the masquerading user is modified or deleted
- Ensure shard routing is consistent between token minting and consumption
- Never replay tokens across environments
When it happens
Trigger: JWT/InstAccess token containing a masquerading_user_uuid that no longer exists (deleted user), a wrong shard_id, or a UUID from a different environment; tokens minted in one environment replayed in another.
Common situations: Users deleted between token issuance and use; cross-environment token reuse (test token in prod); shard misconfiguration; token minted before a data migration.
Understand the failure class
Background: "User not found", "Invalid user", and "does not exist": what missing-user lookup errors mean across Rocket.Chat, LiteLLM, Phabricator, rustfs, and pnpm — this error's family across 10 libraries.
Related errors
- Attachment verifier token expired: #
- Attachment verifier token id mismatch. token id: #
- Cannot generate a services JWT without a 'sub' entry
- refresh window exceeded
- requestor_user is required for JWT generation
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/aa1f5d48bee2727f.
Report an issue: GitHub.
Appendix: source
Thrown at lib/authentication_methods/inst_access_token.rb:89
def self.load_user_and_pseudonym_context(token, domain_root_account)
auth_context = {
current_user: nil,
current_pseudonym: nil,
real_current_user: nil,
real_current_pseudonym: nil
}
auth_context[:current_user] = find_user_by_uuid_prefer_local(token.user_uuid)
return auth_context unless auth_context[:current_user]
auth_context[:current_pseudonym] = SisPseudonym.for(
auth_context[:current_user], domain_root_account, type: :implicit, require_sis: false
)
return auth_context unless auth_context[:current_pseudonym]
if token.masquerading_user_uuid && token.masquerading_user_shard_id
Shard.lookup(token.masquerading_user_shard_id).activate do
real_user = find_user_by_uuid_prefer_local(token.masquerading_user_uuid)
raise AccessTokenError, "masquerading user not found" unless real_user
auth_context[:real_current_user] = real_user
auth_context[:real_current_pseudonym] = SisPseudonym.for(
real_user, domain_root_account, type: :implicit, require_sis: false
)
end
end
auth_context
end
def self.usable_developer_key?(token, domain_root_account)
# The token is not associated with a specific developer key
return true if token.client_id.blank?
DeveloperKey.find_cached(token.client_id).usable_in_context?(domain_root_account)
rescue ActiveRecord::RecordNotFound
# The developer key associated with the 'client_id' claim
# does not exist or was deleted.View on GitHub (pinned to 1c9f0bb801)