{"record":{"id":"b822567faf899148","repo":"langfuse/langfuse","slug":"username-is-required","errorCode":null,"errorMessage":"userName is required","messagePattern":"userName is required","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"web/src/pages/api/public/scim/Users/index.ts","lineNumber":189,"sourceCode":"          });\n        }\n      }\n\n      // A `password` in the request body is accepted and ignored. Setting it\n      // created a usable login credential for an email address nobody had\n      // verified, so an org-scoped key could pre-register an account for\n      // someone else's address. Ignoring rather than rejecting is deliberate:\n      // RFC 7644 3.3 lets a service provider ignore POSTed content, the\n      // attribute is `returned: \"never\"` so no conformant client can observe\n      // the difference, and Okta sends a placeholder password on every create\n      // even when password sync is disabled — rejecting it would break those\n      // syncs. Users authenticate via SSO, or claim the account through the\n      // password-reset flow.\n      const { userName, name, displayName, roles } = body;\n\n      if (!userName) {\n        logger.warn(\"[SCIM] userName is required for user creation\");\n        return res.status(400).json({\n          schemas: [\"urn:ietf:params:scim:api:messages:2.0:Error\"],\n          detail: \"userName is required\",\n          status: 400,\n        });\n      }\n\n      let role: Role = \"NONE\";\n      if (roles && Array.isArray(roles) && roles.length > 0) {\n        const roleSchema = z.array(\n          z.enum([\"OWNER\", \"ADMIN\", \"MEMBER\", \"VIEWER\", \"NONE\"]),\n        );\n        const parsedRoles = roleSchema.safeParse(roles);\n        if (!parsedRoles.success) {\n          logger.warn(\"[SCIM] Invalid roles provided for user creation\");\n          return res.status(400).json({\n            schemas: [\"urn:ietf:params:scim:api:messages:2.0:Error\"],\n            detail: `Invalid roles provided: ${JSON.stringify(roles)}, must be one of OWNER, ADMIN, MEMBER, VIEWER, NONE`,\n            status: 400,","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/langfuse/langfuse/blob/59d92c7cf365150d10b753b5a0d1708902a2ed60/web/src/pages/api/public/scim/Users/index.ts#L171-L207","documentation":"SCIM user creation requires a userName (the user's login/email). If the body lacks userName, creation is rejected with 400 before anything else happens.","triggerScenarios":"POST /api/public/scim/Users with a body that has no userName field (or an empty value).","commonSituations":"IdP attribute mapping not sending the email/login attribute; placeholder test payloads; mapping configured to a custom attribute Langfuse ignores.","solutions":["Set userName in the POST body (typically the user's email)","Fix the IdP's attribute mapping so the email/login attribute maps to userName","Test creation with a minimal known-good payload first"],"exampleFix":"// before\n{ \"schemas\": [...], \"name\": { \"givenName\": \"Jane\" } }\n// after\n{ \"schemas\": [\"urn:ietf:params:scim:schemas:core:2.0:User\"], \"userName\": \"jane@corp.com\", \"name\": { \"givenName\": \"Jane\" } }\n","handlingStrategy":"validation","validationCode":"if (!payload.userName || typeof payload.userName !== 'string') throw new Error('userName (email) is required for SCIM user creation');\n","typeGuard":"const hasUserName = (b: any): b is { userName: string } => typeof b?.userName === 'string' && b.userName.length > 0;","tryCatchPattern":null,"preventionTips":["Map the IdP's primary email attribute to userName","Add contract tests asserting userName presence"],"tags":["scim","validation","http-400","user-creation"],"backgroundTag":"required-field-missing","analyzedSha":"59d92c7cf365150d10b753b5a0d1708902a2ed60","analyzedAt":"2026-08-27T22:22:00.402Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}