ory/hydra · error

flow ForceSubjectIdentifier %s does not match the HandledLog

Error message

flow ForceSubjectIdentifier %s does not match the HandledLoginRequest ForceSubjectIdentifier %s

What it means

Flow.HandleLoginRequest also verifies ForceSubjectIdentifier: if both the Flow and the HandledLoginRequest carry a non-empty ForceSubjectIdentifier they must be identical. This field is set when an upstream flow (e.g. a previous authentication or ID token hint) forced a specific subject, and mismatch means the login was accepted for a different identity than forced.

Source

Thrown at flow/flow.go:314

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.RememberFor
	f.LoginExtendSessionLifespan = h.ExtendSessionLifespan
	f.ACR = h.ACR
	f.AMR = h.AMR
	return nil

View on GitHub (pinned to 4174065ffb)

Solutions

  1. Make the login provider enforce the forced subject (auto-select/pre-authenticate that user) so h.ForceSubjectIdentifier matches the flow
  2. If the forced subject cannot be satisfied, fail the login with an error instead of accepting a different identity
  3. If forcing is no longer desired, create a new login flow without ForceSubjectIdentifier set
  4. Verify you are not copying fields from a different flow into the HandledLoginRequest

Example fix

// before
handled := &flow.HandledLoginRequest{Subject: session.Subject, ForceSubjectIdentifier: session.Subject}
err := flow.HandleLoginRequest(handled)
// after
if flow.ForceSubjectIdentifier != "" && flow.ForceSubjectIdentifier != session.Subject {
    return errors.New("forced subject does not match authenticated user") // reject login
}
handled.ForceSubjectIdentifier = flow.ForceSubjectIdentifier
err := flow.HandleLoginRequest(handled)
Defensive patterns

Strategy: validation

Validate before calling

if flow.ForceSubjectIdentifier != "" {
    if session.Subject != flow.ForceSubjectIdentifier {
        return errors.New("forced subject mismatch: user must re-authenticate as the forced identity")
    }
    handled.ForceSubjectIdentifier = flow.ForceSubjectIdentifier
}
err := flow.HandleLoginRequest(handled)

Try / catch

if err := flow.HandleLoginRequest(handled); err != nil {
    if strings.Contains(err.Error(), "ForceSubjectIdentifier") {
        return redirectToLoginWithError("please authenticate with the required account")
    }
    return err
}

Prevention

When it happens

Trigger: Calling HandleLoginRequest when f.ForceSubjectIdentifier and h.ForceSubjectIdentifier are both set but differ — typically when id_token_hint or a forced subject from an earlier step conflicts with the user that actually authenticated.

Common situations: Using id_token_hint for silent re-authentication but the session belongs to another user; a subject was forced by consent/previous authentication but the login handler let the user log in with a different account; mixing flow objects between requests.

Related errors


AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03). Data as JSON: /api/errors/0590619ee78d549b. Report an issue: GitHub.