{"id":"a60c261c24298fcc","repo":"mongodb/node-mongodb-native","slug":"plain-authentication-mechanism-needs-an-auth-sourc","errorCode":null,"errorMessage":"PLAIN Authentication Mechanism needs an auth source","messagePattern":"PLAIN Authentication Mechanism needs an auth source","errorType":"validation","errorClass":"MongoAPIError","httpStatus":null,"severity":"error","filePath":"src/cmap/auth/mongo_credentials.ts","lineNumber":261,"sourceCode":"          if (typeof host !== 'string') {\n            throw new MongoInvalidArgumentError(ALLOWED_HOSTS_ERROR);\n          }\n        }\n      }\n    }\n\n    if (AUTH_MECHS_AUTH_SRC_EXTERNAL.has(this.mechanism)) {\n      if (this.source != null && this.source !== '$external') {\n        // TODO(NODE-3485): Replace this with a MongoAuthValidationError\n        throw new MongoAPIError(\n          `Invalid source '${this.source}' for mechanism '${this.mechanism}' specified.`\n        );\n      }\n    }\n\n    if (this.mechanism === AuthMechanism.MONGODB_PLAIN && this.source == null) {\n      // TODO(NODE-3485): Replace this with a MongoAuthValidationError\n      throw new MongoAPIError('PLAIN Authentication Mechanism needs an auth source');\n    }\n\n    if (this.mechanism === AuthMechanism.MONGODB_X509 && this.password != null) {\n      if (this.password === '') {\n        Reflect.set(this, 'password', undefined);\n        return;\n      }\n      // TODO(NODE-3485): Replace this with a MongoAuthValidationError\n      throw new MongoAPIError(`Password not allowed for mechanism MONGODB-X509`);\n    }\n\n    const canonicalization = this.mechanismProperties.CANONICALIZE_HOST_NAME ?? false;\n    if (!Object.values(GSSAPICanonicalizationValue).includes(canonicalization)) {\n      throw new MongoAPIError(`Invalid CANONICALIZE_HOST_NAME value: ${canonicalization}`);\n    }\n  }\n\n  static merge(","sourceCodeStart":243,"sourceCodeEnd":279,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/3366c21a6311e02f1be91da982f9b93d3cce99a0/src/cmap/auth/mongo_credentials.ts#L243-L279","documentation":"Thrown for the PLAIN (LDAP) auth mechanism when no authSource is provided. Unlike SCRAM, PLAIN does not default to 'admin'; the driver requires the caller to name the source database explicitly (commonly '$external' for LDAP). This is a MongoAPIError surfaced at validate() time.","triggerScenarios":"In MongoCredentials.validate() when mechanism === MONGODB_PLAIN and source == null.","commonSituations":"Using PLAIN/LDAP auth and forgetting authSource; assuming it defaults like SCRAM; connection string with no authSource and authMechanism=PLAIN.","solutions":["Add authSource=$external (most common for LDAP): 'mongodb://user:pass@host/?authMechanism=PLAIN&authSource=$external'.","Set the authSource to the LDAP-integrated database your deployment expects.","Confirm with the DBA which database backs LDAP auth."],"exampleFix":"// before\n'mongodb://user:pass@host/?authMechanism=PLAIN'\n\n// after\n'mongodb://user:pass@host/?authMechanism=PLAIN&authSource=$external'","handlingStrategy":"validation","validationCode":"function validatePlain(mechanism: string, source?: string) {\n  if (mechanism === 'PLAIN' && source == null) {\n    throw new Error('PLAIN requires authSource (usually $external)');\n  }\n}","typeGuard":"import { MongoAPIError } from 'mongodb';\nfunction isPlainNeedsSource(e: unknown): boolean {\n  return e instanceof MongoAPIError && /PLAIN Authentication Mechanism needs an auth source/.test(e.message);\n}","tryCatchPattern":null,"preventionTips":["Always set authSource=$external for PLAIN/LDAP.","Document LDAP auth requirements in your ops runbook."],"tags":["auth","credentials","configuration","plain","ldap"],"analyzedSha":"3366c21a6311e02f1be91da982f9b93d3cce99a0","analyzedAt":"2026-08-04T13:40:15.335Z","schemaVersion":2}