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
- Only pass session.AuthenticatorAssuranceLevel1 or AuthenticatorAssuranceLevel2 constants; never raw strings.
- Validate any config-driven AAL value before calling (e.g. switch or lookup against known constants).
- Check for case-sensitivity/whitespace issues when converting user input to an AAL level.
- 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
- Always use the exported AuthenticatorAssuranceLevel constants, never raw strings.
- Validate config-supplied AAL values at startup.
- Trim/lowercase any AAL derived from external input before use.
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
- array must not be empty
- the wildcard '*' is not accepted here
- key does not exist in cookie: %+v
- value of key is not of type string in cookie
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)