hcengineering/platform · warning
'text' and 'html' are missing
Error message
'text' and 'html' are missing
What it means
handleSendMail returns HTTP 400 { err: "'text' and 'html' are missing" } when neither text nor html is present in the request body. The mail service requires at least one body representation for the email and refuses the request before contacting the mail backend.
Source
Thrown at services/mail/pod-mail/src/main.ts:97
export async function handleSendMail (
client: MailClient,
req: Request,
res: Response,
ctx: MeasureContext
): Promise<void> {
const { from, to, subject, text, html, attachments, headers, apiKey, password } = req.body
if (process.env.API_KEY !== undefined && process.env.API_KEY !== apiKey) {
ctx.warn('Unauthorized access attempt to send email', {
from,
to
})
res.status(401).send({ err: 'Unauthorized' })
return
}
const fromAddress = from ?? config.source
if (text === undefined && html === undefined) {
ctx.warn('Text and html are missing in email request', { from, to })
res.status(400).send({ err: "'text' and 'html' are missing" })
return
}
if (subject === undefined) {
ctx.warn('Subject is missing in email request', { from, to })
res.status(400).send({ err: "'subject' is missing" })
return
}
if (to === undefined) {
ctx.warn('To address is missing in email request', { from })
res.status(400).send({ err: "'to' is missing" })
return
}
if (fromAddress === undefined) {
ctx.warn('From address is missing in email request', { to })
res.status(400).send({ err: "'from' is missing" })
return
}
const message: SendMailOptions = {View on GitHub (pinned to 63e28dc964)
Solutions
- Include at least one of text or html in the request body.
- Check for typos/field renaming in the client payload (text, html must be top-level body fields).
- Default to a non-empty fallback body when the generated content is empty.
Example fix
// before
const body = { to, subject } // 400: text and html missing
// after
const body = { to, subject, text: text ?? '', html }
if (body.text === '' && body.html === undefined) throw new Error('email body required') Defensive patterns
Strategy: validation
Validate before calling
function assertMailBody(m: { text?: string; html?: string }): void {
if (m.text === undefined && m.html === undefined) {
throw new Error("email requires at least one of 'text' or 'html'")
}
} Type guard
function hasEmailBody(m: { text?: unknown; html?: unknown }): boolean {
return m.text !== undefined || m.html !== undefined
} Try / catch
assertMailBody(mail)
const res = await fetch(mailUrl, { method: 'POST', body: JSON.stringify(mail) })
if (res.status === 400) {
const { err } = await res.json()
throw new Error(`mail rejected: ${err}`)
} Prevention
- Always include text or html when constructing mail payloads.
- Beware serializers that strip undefined fields, silently removing the body.
- Fall back to an empty-string text body when generated content is blank.
- Unit-test payload builders to assert required fields are present.
When it happens
Trigger: POST to the send-mail endpoint with a body lacking both text and html fields — e.g. { to, subject } only, or fields misspelled (body/message instead of text), or an empty JSON body.
Common situations: Building the payload dynamically and skipping body fields when content is empty; sending a template id instead of rendered content; an API client wrapper that drops undefined fields, leaving neither text nor html.
Related errors
- 'subject' is missing
- 'to' is missing
- Failed to load server config
- getDisplayMedia not supported
- No screen access granted
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/6fb3b05110c676a2.
Report an issue: GitHub.