{"record":{"id":"c2cb37716a323421","repo":"hcengineering/platform","slug":"failed-to-ensure-person-exists-for-email-email","errorCode":null,"errorMessage":"Failed to ensure person exists for email: ${email}","messagePattern":"Failed to ensure person exists for email: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"services/mail/mail-common/src/person.ts","lineNumber":55,"sourceCode":"    private readonly restClient: RestClient\n  ) {}\n\n  /**\n   * Gets or creates a person by email address with caching\n   */\n  async ensurePerson (contact: EmailContact): Promise<CachedPerson> {\n    const email = contact.email.toLowerCase().trim()\n\n    let personPromise = this.cache.get(email)\n\n    if (personPromise === undefined) {\n      personPromise = this.fetchAndCachePerson(email, contact.firstName, contact.lastName)\n      this.cache.set(email, personPromise)\n    }\n\n    const result = await personPromise\n    if (result === undefined) {\n      throw new Error(`Failed to ensure person exists for email: ${email}`)\n    }\n    this.emailCache.set(result.socialId, email)\n    return result\n  }\n\n  async getEmailBySocialId (socialId: PersonId): Promise<string | undefined> {\n    return this.emailCache.get(socialId)\n  }\n\n  size (): number {\n    return this.cache.size\n  }\n\n  clearCache (): void {\n    this.cache.clear()\n    this.emailCache.clear()\n  }\n","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/services/mail/mail-common/src/person.ts#L37-L73","documentation":"ensurePerson resolves (or creates and caches) a Person record for an email address. If the cached/returned promise resolves to undefined — the fetch-and-cache path found or produced no person — this Error is thrown because subsequent mail processing requires a concrete Person (socialId).","triggerScenarios":"fetchAndCachePerson returning undefined for the email (creation failed silently or lookup returned nothing) while processing message sender/recipient (fromPerson/toPerson) records.","commonSituations":"Emails from malformed or empty addresses slipping through upstream validation; concurrent processing racing person creation so one path resolves nothing; database issue during person upsert; contact with blank firstName/lastName plus a lookup-only path.","solutions":["Inspect why fetchAndCachePerson returned undefined — check DB errors and whether person creation is permitted in the workspace.","Validate the email is non-empty and well-formed before calling ensurePerson (see also 'Invalid email address').","Catch the error and skip/queue the message for retry instead of failing the whole ingestion pipeline.","Check for creation races; make fetchAndCachePerson's upsert idempotent and always return the person."],"exampleFix":"// before\nconst person = await service.ensurePerson(ctx, email) // throws if undefined\n// after\nif (!email || !email.includes('@')) {\n  throw new Error(`Skipping message: bad sender email \"${email}\"`)\n}\nconst person = await service.ensurePerson(ctx, email)","handlingStrategy":"try-catch","validationCode":"if (typeof email !== 'string' || !email.includes('@')) {\n  throw new Error(`ensurePerson requires a valid email, got: ${email}`)\n}","typeGuard":"function isValidEmail(email: string): boolean {\n  return /^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$/.test(email)\n}","tryCatchPattern":"try {\n  person = await service.ensurePerson(ctx, email)\n} catch (err) {\n  if (err.message.startsWith('Failed to ensure person exists')) {\n    console.warn(`Skipping message from unresolvable person: ${email}`)\n    return // or queue for retry\n  }\n  throw err\n}","preventionTips":["Validate sender/recipient emails before message processing.","Monitor person creation failures — they usually indicate DB or permission problems.","Handle empty/placeholder addresses ('undisclosed-recipients') before calling ensurePerson."],"tags":["mail","person-resolution","database","validation"],"backgroundTag":"person-not-found","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}