{"record":{"id":"803686c4724c52bc","repo":"RocketChat/Rocket.Chat","slug":"customoauth-failed-to-extract-username-803686","errorCode":null,"errorMessage":"CustomOAuth: Failed to extract username","messagePattern":"CustomOAuth: Failed to extract username","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/lib/auth-providers/custom-oauth/custom_oauth_server.js","lineNumber":323,"sourceCode":"\t\t\tconst error = new Error(`Failed to fetch emails from ${this.name} at ${this.emailPath}. ${err.message}`);\n\t\t\tthrow _.extend(error, { response: err.response });\n\t\t}\n\t}\n\n\tretrieveCredential(credentialToken, credentialSecret) {\n\t\treturn OAuth.retrieveCredential(credentialToken, credentialSecret);\n\t}\n\n\tgetUsername(data) {\n\t\ttry {\n\t\t\tconst value = fromTemplate(this.usernameField, data);\n\n\t\t\tif (!value) {\n\t\t\t\tthrow new Meteor.Error('field_not_found', `Username field \"${this.usernameField}\" not found in data`, data);\n\t\t\t}\n\t\t\treturn value;\n\t\t} catch (error) {\n\t\t\tthrow new Error('CustomOAuth: Failed to extract username', error.message);\n\t\t}\n\t}\n\n\tgetEmail(data) {\n\t\ttry {\n\t\t\tconst value = fromTemplate(this.emailField, data);\n\n\t\t\tif (!value) {\n\t\t\t\tthrow new Meteor.Error('field_not_found', `Email field \"${this.emailField}\" not found in data`, data);\n\t\t\t}\n\t\t\treturn value;\n\t\t} catch (error) {\n\t\t\tthrow new Error('CustomOAuth: Failed to extract email', error.message);\n\t\t}\n\t}\n\n\tgetCustomName(data) {\n\t\ttry {","sourceCodeStart":305,"sourceCodeEnd":341,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/lib/auth-providers/custom-oauth/custom_oauth_server.js#L305-L341","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Turn on CustomOAuth debug logs and capture the payload printed with 'Username field not found in data'","Fix the usernameField value: a plain dot path that exists in the payload, or a syntactically valid '{{/regex/::path}}' formula","Validate the regex part with new RegExp() in a scratch shell before saving the setting","Clear Username Field entirely if strict username mapping is not required"],"exampleFix":"// before: Username Field = '{{/^(.+)@/::email}}' but the IdP does not return e-mail -> extraction throws\n// Error: CustomOAuth: Failed to extract username ...\n\n// after: Username Field = 'preferred_username'","handlingStrategy":"validation","validationCode":"// run once when saving OAuth settings\nconst assertTemplateOk = (tpl: string, sample: Record<string, unknown>) => {\n  try {\n    fromTemplate(tpl, sample);\n  } catch (e) {\n    throw new Error(`Username Field template invalid: ${e.message}`);\n  }\n};","typeGuard":"const isHealthyTemplate = (tpl: string | undefined, sample: Record<string, unknown>): boolean => {\n  if (!tpl) return false;\n  try {\n    return fromTemplate(tpl, sample) != null;\n  } catch {\n    return false;\n  }\n};","tryCatchPattern":"try {\n  identity.username = strategy.getUsername(identity);\n} catch (error) {\n  if (/Failed to extract username/.test(error.message)) {\n    return done(new Meteor.Error('oauth-username-mapping', 'Username mapping misconfigured. Contact admin.'));\n  }\n  throw error;\n}","preventionTips":["Smoke-test every field template against a real payload before saving","Do one manual SSO login after any IdP upgrade before announcing the feature","Keep field templates as plain dot-paths unless a regex is truly required"],"tags":["oauth","custom-oauth","username","field-mapping","error-wrapping"],"backgroundTag":"oauth-identity-field-mapping-failed","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}