RocketChat/Rocket.Chat · error · Error

CustomOAuth: Failed to extract username

Error message

CustomOAuth: Failed to extract username

What it means

getUsername()'s catch block converts any failure - the inner field_not_found Meteor.Error, a SyntaxError from an invalid regex in the template, or a TypeError from a malformed path - into a plain Error('CustomOAuth: Failed to extract username', <inner message>). It fires during normalizeIdentity right after the identity endpoint responds and aborts the login. The second argument is just the inner message string, so the original Meteor error code and payload details are lost.

Source

Thrown at apps/meteor/server/lib/auth-providers/custom-oauth/custom_oauth_server.js:323

			const error = new Error(`Failed to fetch emails from ${this.name} at ${this.emailPath}. ${err.message}`);
			throw _.extend(error, { response: err.response });
		}
	}

	retrieveCredential(credentialToken, credentialSecret) {
		return OAuth.retrieveCredential(credentialToken, credentialSecret);
	}

	getUsername(data) {
		try {
			const value = fromTemplate(this.usernameField, data);

			if (!value) {
				throw new Meteor.Error('field_not_found', `Username field "${this.usernameField}" not found in data`, data);
			}
			return value;
		} catch (error) {
			throw new Error('CustomOAuth: Failed to extract username', error.message);
		}
	}

	getEmail(data) {
		try {
			const value = fromTemplate(this.emailField, data);

			if (!value) {
				throw new Meteor.Error('field_not_found', `Email field "${this.emailField}" not found in data`, data);
			}
			return value;
		} catch (error) {
			throw new Error('CustomOAuth: Failed to extract email', error.message);
		}
	}

	getCustomName(data) {
		try {

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Turn on CustomOAuth debug logs and capture the payload printed with 'Username field not found in data'
  2. Fix the usernameField value: a plain dot path that exists in the payload, or a syntactically valid '{{/regex/::path}}' formula
  3. Validate the regex part with new RegExp() in a scratch shell before saving the setting
  4. Clear Username Field entirely if strict username mapping is not required

Example fix

// before: Username Field = '{{/^(.+)@/::email}}' but the IdP does not return e-mail -> extraction throws
// Error: CustomOAuth: Failed to extract username ...

// after: Username Field = 'preferred_username'
Defensive patterns

Strategy: validation

Validate before calling

// run once when saving OAuth settings
const assertTemplateOk = (tpl: string, sample: Record<string, unknown>) => {
  try {
    fromTemplate(tpl, sample);
  } catch (e) {
    throw new Error(`Username Field template invalid: ${e.message}`);
  }
};

Type guard

const isHealthyTemplate = (tpl: string | undefined, sample: Record<string, unknown>): boolean => {
  if (!tpl) return false;
  try {
    return fromTemplate(tpl, sample) != null;
  } catch {
    return false;
  }
};

Try / catch

try {
  identity.username = strategy.getUsername(identity);
} catch (error) {
  if (/Failed to extract username/.test(error.message)) {
    return done(new Meteor.Error('oauth-username-mapping', 'Username mapping misconfigured. Contact admin.'));
  }
  throw error;
}

Prevention

When it happens

Trigger: Same conditions as the inner field_not_found error (usernameField path absent from the identity payload, regex formula not matching), plus template syntax problems: an invalid regex inside '{{/.../::path}}' that throws in new RegExp(), or usernameField being undefined so getNestedValue throws on undefined.split when getUsername is called directly.

Common situations: Admin typos the Username Field setting; provider payload shape changes after an IdP upgrade; strategy constructed without usernameField but getUsername invoked directly; copy-pasted formula containing smart quotes or missing braces.

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18). Data as JSON: /api/errors/803686c4724c52bc. Report an issue: GitHub.