knadh/listmonk · error

globals.messages.invalidFields

Error message

globals.messages.invalidFields

What it means

In OIDCFinish (cmd/auth.go), after a successful OIDC callback the ID token claims are inspected and the email claim is extracted. If the trimmed claim email is empty, the login page is re-rendered with a localized 'invalid fields' error naming the email field. The library throws it because it refuses to link an OIDC identity to a local account without a usable e-mail address.

Source

Thrown at cmd/auth.go:235

	// Validate the state.
	var state oidcState
	stateB, err := base64.URLEncoding.DecodeString(c.QueryParam("state"))
	if err != nil {
		a.log.Printf("error decoding OIDC state: %v", err)
		return echo.NewHTTPError(http.StatusInternalServerError, a.i18n.T("globals.messages.internalError"))
	}
	if err := json.Unmarshal(stateB, &state); err != nil {
		a.log.Printf("error unmarshalling OIDC state: %v", err)
		return echo.NewHTTPError(http.StatusInternalServerError, a.i18n.T("globals.messages.internalError"))
	}
	if state.Nonce != nonce.Value {
		return a.renderLoginPage(c, echo.NewHTTPError(http.StatusUnauthorized, a.i18n.T("users.invalidRequest")))
	}

	// Validate e-mail from the claim.
	email := strings.TrimSpace(claims.Email)
	if email == "" {
		return a.renderLoginPage(c, errors.New(a.i18n.Ts("globals.messages.invalidFields", "name", "email")))
	}
	em, err := mail.ParseAddress(email)
	if err != nil {
		return a.renderLoginPage(c, err)
	}
	email = strings.ToLower(em.Address)
	claims.Email = email

	// Get the user by e-mail received from OIDC.
	user, userErr := a.core.GetUser(0, "", email)
	if userErr != nil {
		// If the user doesn't exist, and auto-creation is enabled, create a new user.
		if httpErr, ok := userErr.(*echo.HTTPError); ok && httpErr.Code == http.StatusNotFound && a.cfg.Security.OIDC.AutoCreateUsers {
			u, err := a.createOIDCUser(claims, c)
			if err != nil {
				return a.renderLoginPage(c, err)
			}
			user = u

View on GitHub (pinned to 670c01717d)

Solutions

  1. Add the 'email' (and usually 'profile') scope to the OIDC client configuration so the provider returns the email claim.
  2. In the identity provider, ensure users have a verified primary e-mail address set.
  3. Check that claims are correctly mapped: some providers nest email under a different claim; configure claim mapping or a custom claims provider.
  4. Show a clearer message to the user advising them to contact their admin if their provider cannot supply an e-mail.

Example fix

// before
scopes := []string{"openid"}
// after
scopes := []string{"openid", "email", "profile"}
Defensive patterns

Strategy: validation

Validate before calling

// before calling the OIDC finish endpoint, ensure the provider returns email
const hasEmail = !!(claims && typeof claims.email === 'string' && claims.email.trim().length > 0);
if (!hasEmail) throw new Error('OIDC provider did not return an email claim');

Type guard

function hasEmailClaim(c: unknown): c is { email: string } {
  return typeof c === 'object' && c !== null && 'email' in c && typeof (c as any).email === 'string' && (c as any).email.trim() !== '';
}

Try / catch

try {
  const res = await fetch(oidcFinishURL, { redirect: 'follow' });
} catch (e) {
  if (String(e).includes('invalidFields')) {
    showError('Your identity provider did not provide an e-mail address; contact your admin.');
  }
}

Prevention

When it happens

Trigger: Completing the OIDC login flow (GET the OIDC finish/callback endpoint) when the ID token issued by the identity provider has an empty or missing email claim after strings.TrimSpace(claims.Email).

Common situations: Identity providers (e.g. Keycloak, Azure AD, Google) configured without the 'email' scope, users with no primary e-mail set, or OIDC clients whose requested scopes do not include the profile/email scopes so claims.Email stays empty.

Related errors


AI-assisted analysis of knadh/listmonk@670c01717d (2026-09-01). Data as JSON: /api/errors/c7c9d0ba90b09ec9. Report an issue: GitHub.