usememos/memos · error

config.oauth2Config.fieldMapping.identifier is required

Error message

config.oauth2Config.fieldMapping.identifier is required

What it means

Thrown when config.oauth2Config in a memos-idp-*.json file has no fieldMapping message or its identifier field is blank after trimming. The fieldMapping.identifier tells Memos which userinfo JSON property (e.g. "login", "email", "sub") identifies the user; without it the OAuth2 exchange cannot map a login to a Memos account, so the deployment file is rejected at startup.

Source

Thrown at store/deployment_config.go:217

		{name: "authUrl", value: config.AuthUrl},
		{name: "tokenUrl", value: config.TokenUrl},
		{name: "userInfoUrl", value: config.UserInfoUrl},
	} {
		parsed, err := url.ParseRequestURI(field.value)
		if err != nil || (parsed.Scheme != "http" && parsed.Scheme != "https") || parsed.Host == "" {
			return errors.Errorf("config.oauth2Config.%s must be an absolute HTTP(S) URL", field.name)
		}
	}
	if len(config.Scopes) == 0 {
		return errors.New("config.oauth2Config.scopes is required")
	}
	for i, scope := range config.Scopes {
		if strings.TrimSpace(scope) == "" {
			return errors.Errorf("config.oauth2Config.scopes[%d] must not be empty", i)
		}
	}
	if config.FieldMapping == nil || strings.TrimSpace(config.FieldMapping.Identifier) == "" {
		return errors.New("config.oauth2Config.fieldMapping.identifier is required")
	}
	return nil
}

func validateAndNormalizeDeploymentInstanceSetting(setting *storepb.InstanceSetting) error {
	switch setting.Key {
	case storepb.InstanceSettingKey_GENERAL:
		if setting.GetGeneralSetting() == nil {
			return errors.New("generalSetting must be populated for key GENERAL")
		}
		if offset := setting.GetGeneralSetting().WeekStartDayOffset; offset < -1 || offset > 6 {
			return errors.New("generalSetting.weekStartDayOffset must be between -1 and 6")
		}
	case storepb.InstanceSettingKey_STORAGE:
		storage := setting.GetStorageSetting()
		if storage == nil {
			return errors.New("storageSetting must be populated for key STORAGE")
		}

View on GitHub (pinned to 14d757ce1f)

Solutions

  1. Add "fieldMapping": { "identifier": "<userinfo-key>" } under config.oauth2Config.
  2. For GitHub use "login"; for OIDC-compliant providers use "sub" or "email" depending on the userinfo payload.

Example fix

// before
"oauth2Config": { ..., "scopes": ["read:user"] }

// after
"oauth2Config": { ..., "scopes": ["read:user"], "fieldMapping": { "identifier": "login" } }
Defensive patterns

Strategy: validation

Validate before calling

fm := cfg.GetFieldMapping()
if fm == nil || strings.TrimSpace(fm.Identifier) == "" {
    return errors.New("config.oauth2Config.fieldMapping.identifier is required")
}

Type guard

func hasIdentifierMapping(cfg *storepb.OAuth2Config) bool {
    fm := cfg.GetFieldMapping()
    return fm != nil && strings.TrimSpace(fm.GetIdentifier()) != ""
}

Prevention

When it happens

Trigger: config.oauth2Config with "fieldMapping": {}, a missing "fieldMapping" key, or "identifier": "" / " ".

Common situations: Not knowing which userinfo attribute the provider returns (e.g. GitHub uses "login", generic OIDC uses "sub" or "email"); trimming the JSON down for testing and removing fieldMapping.

Related errors


AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15). Data as JSON: /api/errors/fea0019b1e5a61e5. Report an issue: GitHub.