ory/hydra · error
flow Subject %s does not match the HandledLoginRequest Subje
Error message
flow Subject %s does not match the HandledLoginRequest Subject %s
What it means
Flow.HandleLoginRequest rejects a HandledLoginRequest whose Subject differs from the Subject already stored on the Flow. Hydra flows pin the authenticated user at login initialization; accepting a different subject later would let the same flow be reused to impersonate another user, so the mismatch is treated as a hard error.
Source
Thrown at flow/flow.go:310
}
// InvalidateDeviceRequest shifts the flow state to DeviceFlowStateUsed. This
// transition is executed upon device completion.
func (f *Flow) InvalidateDeviceRequest() error {
if err := f.State.IsAny(DeviceFlowStateUnused); err != nil {
return err
}
f.State = DeviceFlowStateUsed
return nil
}
func (f *Flow) HandleLoginRequest(h *HandledLoginRequest) error {
if err := f.State.IsAny(FlowStateLoginInitialized, FlowStateLoginUnused, FlowStateLoginError); err != nil {
return err
}
if f.Subject != "" && h.Subject != "" && f.Subject != h.Subject {
return errors.Errorf("flow Subject %s does not match the HandledLoginRequest Subject %s", f.Subject, h.Subject)
}
if f.ForceSubjectIdentifier != "" && h.ForceSubjectIdentifier != "" && f.ForceSubjectIdentifier != h.ForceSubjectIdentifier {
return errors.Errorf("flow ForceSubjectIdentifier %s does not match the HandledLoginRequest ForceSubjectIdentifier %s", f.ForceSubjectIdentifier, h.ForceSubjectIdentifier)
}
f.State = FlowStateLoginUnused
if f.Context != nil {
f.Context = h.Context
}
f.Subject = h.Subject
f.ForceSubjectIdentifier = h.ForceSubjectIdentifier
f.IdentityProviderSessionID = sqlxx.NullString(h.IdentityProviderSessionID)
f.LoginRemember = h.Remember
f.LoginRememberFor = h.RememberForView on GitHub (pinned to 4174065ffb)
Solutions
- Ensure the subject that accepted the login equals the flow's stored Subject before calling HandleLoginRequest; abort and re-initialize the flow if the user changed
- Fetch the flow fresh from storage and re-run the login provider so the HandledLoginRequest reflects the current authenticated subject
- If the user genuinely changed, create a new login flow (new challenge) instead of reusing the old one
- Check that you are not passing a HandledLoginRequest belonging to another flow (mixed-up objects/keys)
Example fix
// before
handled := &flow.HandledLoginRequest{Subject: currentUser.Subject, Context: ...}
err := loginFlow.HandleLoginRequest(handled) // panics/errors if subject differs
// after
if loginFlow.Subject != "" && currentUser.Subject != loginFlow.Subject {
loginFlow, err = newLoginFlowFor(currentUser) // create a fresh flow
if err != nil { return err }
}
err := loginFlow.HandleLoginRequest(handled) Defensive patterns
Strategy: validation
Validate before calling
if loginFlow.Subject != "" && handled.Subject != "" && loginFlow.Subject != handled.Subject {
return fmt.Errorf("flow subject %s != handled subject %s; re-initialize login flow", loginFlow.Subject, handled.Subject)
}
err := loginFlow.HandleLoginRequest(handled) Try / catch
if err := flow.HandleLoginRequest(handled); err != nil {
if strings.Contains(err.Error(), "does not match the HandledLoginRequest Subject") {
flow, err = reinitializeLoginFlow(authRequest)
}
return err
} Prevention
- Always fetch the flow fresh from storage immediately before calling HandleLoginRequest
- Re-run your login provider on every request instead of caching a completed HandledLoginRequest across sessions
- Reject a login (error prompt) when the authenticated subject differs from the flow's subject
- Key flows by challenge ID and never share HandledLoginRequest objects between flows
When it happens
Trigger: Calling Flow.HandleLoginRequest (public) when both f.Subject and h.Subject are non-empty and unequal — e.g. the login flow was initialized/claimed for user A but the LoginRequestHandler resolved user B, or the flow was fetched twice and completed with a different login session.
Common situations: Reusing a stale login challenge after the user logged out and in as a different account; cookie/session swapping between flow creation and login acceptance; multiple browser tabs completing the same flow with different identities; replaying a saved HandledLoginRequest object from a previous authentication.
Related errors
- flow ForceSubjectIdentifier %s does not match the HandledLog
- issuer URL must be set unless development mode is enabled
- Only access tokens are allowed in the authorization header.
- invalid flow state: expected one of %v, got %d
- issuer URL scheme must be HTTPS unless development mode is e
AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03).
Data as JSON: /api/errors/6c3e9bc64d6d4be3.
Report an issue: GitHub.