{"record":{"id":"aa8ade5f9464b844","repo":"calcom/cal.diy","slug":"invalid-email-trimmed","errorCode":null,"errorMessage":"Invalid email ${trimmed}","messagePattern":"Invalid email (.+?)","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"warning","filePath":"apps/api/v2/src/modules/oauth-clients/controllers/oauth-client-users/inputs/get-managed-users.input.ts","lineNumber":15,"sourceCode":"import { BadRequestException } from \"@nestjs/common\";\nimport { ApiPropertyOptional } from \"@nestjs/swagger\";\nimport { Transform } from \"class-transformer\";\nimport { ArrayNotEmpty, isEmail, IsOptional } from \"class-validator\";\n\nimport { Pagination } from \"@calcom/platform-types\";\n\nexport class GetManagedUsersInput extends Pagination {\n  @IsOptional()\n  @Transform(({ value }) => {\n    if (typeof value === \"string\") {\n      return value.split(\",\").map((email: string) => {\n        const trimmed = email.trim();\n        if (!isEmail(trimmed)) {\n          throw new BadRequestException(`Invalid email ${trimmed}`);\n        }\n        return trimmed;\n      });\n    }\n    return value;\n  })\n  @ArrayNotEmpty({ message: \"emails cannot be empty.\" })\n  @ApiPropertyOptional({\n    description:\n      \"Filter managed users by email. If you want to filter by multiple emails, separate them with a comma.\",\n    example: \"?emails=email1@example.com,email2@example.com\",\n  })\n  emails?: string[];\n}\n","sourceCodeStart":1,"sourceCodeEnd":30,"githubUrl":"https://github.com/calcom/cal.diy/blob/176037d0afbe572f870a3c702985e7cd83fe6c0c/apps/api/v2/src/modules/oauth-clients/controllers/oauth-client-users/inputs/get-managed-users.input.ts#L1-L30","documentation":"Thrown inside the GetManagedUsersInput DTO's @Transform on the `emails` field. When emails is provided as a comma-separated string, each value is split and trimmed; any token failing class-validator's isEmail check raises BadRequestException (HTTP 400) with the offending value interpolated. This validates the query param before the handler runs.","triggerScenarios":"GET request to the managed-users endpoint with ?emails= containing one or more malformed addresses, e.g. ?emails=foo, ?emails=a@b,c, ?emails=foo@bar@baz. The Transform throws during validation pipe processing.","commonSituations":"User types emails manually with typos; copy-paste includes trailing commas or spaces that yield empty tokens after split; mixed format like 'Name <a@b.com>' instead of bare address; trailing semicolon separators instead of commas.","solutions":["Sanitize the emails list client-side: trim, drop empties, validate with an email regex before sending.","Use commas only as separators and ensure each token matches a standard email pattern.","Send the request without the emails param if you want all managed users, since the field is @IsOptional."],"exampleFix":"// before\n?emails=foo,b ar@example.com\n\n// after\nconst clean = raw.split(',').map(s=>s.trim()).filter(Boolean).filter(isEmailFormat);\n?emails=foo@example.com,bar@example.com","handlingStrategy":"validation","validationCode":"const emails = raw.split(',').map(s => s.trim()).filter(Boolean);\nconst invalid = emails.filter(e => !isEmail(e));\nif (invalid.length) {\n  throw new Error(`Invalid emails: ${invalid.join(', ')}`);\n}\n// then send ?emails=emails.join(',')","typeGuard":"const allValidEmails = (arr: string[]): boolean => arr.every(e => isEmail(e));","tryCatchPattern":null,"preventionTips":["Trim and drop empty tokens before sending the emails param.","Validate with the same isEmail rule client-side.","Omit the param entirely when no filter is needed."],"tags":["oauth-clients","dto","validation","email","class-validator","nestjs"],"backgroundTag":null,"analyzedSha":"176037d0afbe572f870a3c702985e7cd83fe6c0c","analyzedAt":"2026-08-12T19:12:41.464Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}