ory/kratos · error · errors.Errorf

requested unknown aal

Error message

requested unknown aal: %s

What it means

DoesSessionSatisfy on ManagerHTTP maps a requested AuthenticationMethodLevel (aal1/aal2) to a check against the session. If requestedAAL is anything other than the known levels, the manager cannot evaluate it and returns this error. It indicates a programming/configuration mistake rather than a session state problem.

Solutions

  1. Only pass session.AuthenticatorAssuranceLevel1 or AuthenticatorAssuranceLevel2 constants; never raw strings.
  2. Validate any config-driven AAL value before calling (e.g. switch or lookup against known constants).
  3. Check for case-sensitivity/whitespace issues when converting user input to an AAL level.
  4. Upgrade the library if you need a higher AAL than the current version supports.

Example fix

// before
err = s.DoesSessionSatisfy(ctx, req, "aal3")
// after
err = s.DoesSessionSatisfy(ctx, req, session.AuthenticatorAssuranceLevel2)
Defensive patterns

Strategy: validation

Validate before calling

func validAAL(l session.AuthenticationMethodLevel) bool {
  return l == session.AuthenticatorAssuranceLevel1 || l == session.AuthenticatorAssuranceLevel2
}

Type guard

func isKnownAAL(s string) bool {
  switch s {
  case "aal1", "aal2":
    return true
  }
  return false
}

Try / catch

if err := s.DoesSessionSatisfy(ctx, req, aal); err != nil {
  if strings.HasPrefix(err.Error(), "requested unknown aal") {
    return fmt.Errorf("invalid aal configured: %q", aal)
  }
  return err
}

Prevention

When it happens

Trigger: Calling DoesSessionSatisfy (directly or via session validation middleware) with an AuthenticationMethodLevel value that is not AAL1 or AAL2 — e.g. an empty string, a raw "aal3", or a misparsed config value passed as the requested AAL.

Common situations: Custom code constructing an AuthenticationMethodLevel from user input or config without validating it, typo like "aal" or "AAL1" (case-sensitive), or a newer AAL value used against an older library version.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of ory/kratos@b86338da04 (2026-09-07). Data as JSON: /api/errors/dc73a2e8344fba7b. Report an issue: GitHub.

Appendix: source

Thrown at session/manager_http.go:435

		case identity.AuthenticatorAssuranceLevel1:
			// The identity has AAL1, the session has AAL1, we're good.
			return nil
		case identity.AuthenticatorAssuranceLevel2:
			// The identity has AAL2, the session has AAL1, we need to upgrade the session.

			// Since we ended up here, it also means that `sess.Identity.InternalAvailableAAL` was `aal1` and is now `aal2`.
			// Let's update the database.
			if managerOpts.upsertAAL {
				if err := s.r.PrivilegedIdentityPool().UpdateIdentityColumns(ctx, sess.Identity, "available_aal"); err != nil {
					return err
				}
			}
		}

		return NewErrAALNotSatisfied(loginURL.String())
	}

	return errors.Errorf("requested unknown aal: %s", requestedAAL)
}

func (s *ManagerHTTP) SessionAddAuthenticationMethods(ctx context.Context, sid uuid.UUID, ams ...AuthenticationMethod) (err error) {
	ctx, span := s.r.Tracer(ctx).Tracer().Start(ctx, "sessions.ManagerHTTP.SessionAddAuthenticationMethods")
	defer otelx.End(span, &err)

	// Since we added the method, it also means that we have authenticated it
	sess, err := s.r.SessionPersister().GetSession(ctx, sid, ExpandNothing)
	if err != nil {
		return err
	}
	for _, m := range ams {
		sess.CompletedLoginForMethod(m)
	}
	// Completing an authentication method is an authentication event, so the
	// session's authenticated_at is refreshed as well. This matches login
	// flows, which set authenticated_at when a second factor completes.
	sess.AuthenticatedAt = time.Now().UTC()

View on GitHub (pinned to b86338da04)