{"record":{"id":"4febf6ff88e6c609","repo":"hcengineering/platform","slug":"subject-is-missing","errorCode":null,"errorMessage":"'subject' is missing","messagePattern":"'subject' is missing","errorType":"http","errorClass":null,"httpStatus":400,"severity":"warning","filePath":"services/mail/pod-mail/src/main.ts","lineNumber":102,"sourceCode":"): Promise<void> {\n  const { from, to, subject, text, html, attachments, headers, apiKey, password } = req.body\n  if (process.env.API_KEY !== undefined && process.env.API_KEY !== apiKey) {\n    ctx.warn('Unauthorized access attempt to send email', {\n      from,\n      to\n    })\n    res.status(401).send({ err: 'Unauthorized' })\n    return\n  }\n  const fromAddress = from ?? config.source\n  if (text === undefined && html === undefined) {\n    ctx.warn('Text and html are missing in email request', { from, to })\n    res.status(400).send({ err: \"'text' and 'html' are missing\" })\n    return\n  }\n  if (subject === undefined) {\n    ctx.warn('Subject is missing in email request', { from, to })\n    res.status(400).send({ err: \"'subject' is missing\" })\n    return\n  }\n  if (to === undefined) {\n    ctx.warn('To address is missing in email request', { from })\n    res.status(400).send({ err: \"'to' is missing\" })\n    return\n  }\n  if (fromAddress === undefined) {\n    ctx.warn('From address is missing in email request', { to })\n    res.status(400).send({ err: \"'from' is missing\" })\n    return\n  }\n  const message: SendMailOptions = {\n    from: fromAddress,\n    to,\n    subject,\n    text\n  }","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/services/mail/pod-mail/src/main.ts#L84-L120","documentation":"handleSendMail returns HTTP 400 { err: \"'subject' is missing\" } when the subject field is absent from the request body. This validation runs after the text/html check and before the recipient check.","triggerScenarios":"POST to the send-mail endpoint with text or html present but subject undefined — e.g. { to, text } only, subject explicitly set to undefined by a serializer that drops it, or a client wrapper that omits empty subjects.","commonSituations":"Automated notification builders that treat subject as optional; JSON.stringify dropping undefined subject values; migrating from a mail API where subject was optional to pod-mail where it is required.","solutions":["Always include a non-undefined subject string in the request body.","If the subject is optional in your domain, pass an explicit empty string '' instead of undefined.","Fix client serializers that strip undefined/empty fields before send."],"exampleFix":"// before\nsendMail({ to, text, subject: maybeSubject }) // undefined subject -> 400\n// after\nsendMail({ to, text, subject: maybeSubject ?? '' })","handlingStrategy":"validation","validationCode":"function assertSubject(m: { subject?: string }): void {\n  if (m.subject === undefined) throw new Error(\"email requires a 'subject' field (use '' if intentionally empty)\")\n}","typeGuard":"function hasSubject(m: { subject?: unknown }): m is { subject: string } {\n  return m.subject !== undefined\n}","tryCatchPattern":"if (!hasSubject(mail)) mail.subject = ''\nconst res = await fetch(mailUrl, { method: 'POST', body: JSON.stringify(mail) })\nif (res.status === 400) throw new Error(`mail rejected: ${(await res.json()).err}`)","preventionTips":["Treat subject as required even if your domain considers it optional; pass '' instead of undefined.","Remember JSON.stringify drops undefined properties.","Keep client mail wrappers aligned with pod-mail's required-field list (subject, to, text/html).","Add pre-send payload validation in shared mail utilities."],"tags":["http-400","request-validation","mail"],"backgroundTag":"missing-request-parameter","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}