instructure/canvas-lms · warning · ImpossibleCredentialsError

pseudonym cannot have a unique_id of length #

Error message

pseudonym cannot have a unique_id of length #{credentials[:unique_id].length}

What it means

Pseudonym raises ImpossibleCredentialsError during login credential processing when the supplied unique_id (login/email) exceeds 255 characters. Such credentials can never succeed because the column limit makes them impossible to match, and past behavior produced noisy errors instead of a clean failed login.

Solutions

  1. Return a normal failed-login response instead of a 500 — the raise exists so callers rescue ImpossibleCredentialsError and treat it as bad credentials
  2. Add client-side/server-side length validation (<= 255) on the login field before authentication
  3. Investigate the client or integration producing >255-char unique_ids
  4. Sanitize/trim login input at the edge (proxy, SSO adapter) before it reaches Pseudonym

Example fix

// before
login(params[:pseudonym_session][:unique_id])
// after
uid = params[:pseudonym_session][:unique_id]
if uid && uid.length > 255
  return failed_login
end
login(uid)
Defensive patterns

Strategy: validation

Validate before calling

uid = params.dig(:pseudonym_session, :unique_id)
return failed_login if uid.blank? || uid.length > 255

Type guard

def valid_unique_id?(uid)
  uid.is_a?(String) && uid.length.between?(1, 255)
end

Try / catch

begin
  authenticate(pseudonym_session)
rescue ImpossibleCredentialsError
  failed_login
end

Prevention

When it happens

Trigger: A login attempt where credentials[:unique_id].length > 255 — e.g. a malicious or malformed POST to the login endpoint, a client bug concatenating values into the login field, or pasted oversized data into the login form.

Common situations: Bots or scanners submitting garbage to /login; SSO/LDAP misconfiguration sending oversized identifiers; user pasting a long string (e.g. a JWT or URL) into the email field; automated tests with invalid fixtures.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15). Data as JSON: /api/errors/d757cfb4eda3e6c1. Report an issue: GitHub.

Appendix: source

Thrown at app/models/pseudonym.rb:771

  scope :active_only, -> { where(workflow_state: "active") }
  scope :deleted, -> { where(workflow_state: "deleted") }

  def self.serialization_excludes
    %i[crypted_password password_salt reset_password_token persistence_token single_access_token perishable_token sis_ssha]
  end

  def self.associated_shards(_unique_id_or_sis_user_id)
    [Shard.default]
  end

  def self.find_all_by_arbitrary_credentials(credentials, account_ids)
    return [] if credentials[:unique_id].blank? ||
                 credentials[:password].blank?
    if credentials[:unique_id].length > 255
      # this sometimes happens by mistake, and produces noisy errors.
      # we can handle this error explicitly when it arrives and just return
      # a failed login instead of an error.
      raise ImpossibleCredentialsError, "pseudonym cannot have a unique_id of length #{credentials[:unique_id].length}"
    end

    error = nil
    begin
      associated_shards = associated_shards(credentials[:unique_id])
    rescue => e
      # global lookups is just an optimization anyway; log an error, but continue
      # by searching all accounts the slow way
      Canvas::Errors.capture(e)
    end
    pseudonyms = Shard.partition_by_shard(account_ids) do |shard_account_ids|
      next if GlobalLookups.enabled? && associated_shards && !associated_shards.include?(Shard.current)

      active_only
        .by_unique_id(credentials[:unique_id])
        .where(account_id: shard_account_ids)
        .preload(:user)
        .select do |p|

View on GitHub (pinned to 1c9f0bb801)