TryGhost/Ghost · error · ValidationError
Subject is required
Error message
Subject is required
What it means
A ValidationError thrown by the automation email preview input validator when the request frame's `data.subject` is missing, not a string, or whitespace-only. The validator runs for both the `preview` and `sendTestEmail` automation endpoints before any email rendering happens, so a blank subject short-circuits the whole call. It is a client-side input error, not a server fault.
Source
Thrown at ghost/core/core/server/api/endpoints/utils/validators/input/automation_email_previews.js:21
const validator = require('@tryghost/validator');
const {ValidationError} = require('@tryghost/errors');
const tpl = require('@tryghost/tpl');
const lexicalLib = require('../../../../../lib/lexical');
const messages = {
invalidEmailReceived: 'The server did not receive a valid email',
invalidLexical: 'Lexical must be a well-formed Lexical document',
subjectRequired: 'Subject is required',
lexicalRequired: 'Email content is required'
};
const validatePreviewData = async (frame) => {
const subject = frame.data.subject;
const lexical = frame.data.lexical;
if (typeof subject !== 'string' || !subject.trim()) {
throw new ValidationError({
message: tpl(messages.subjectRequired),
property: 'subject'
});
}
if (typeof lexical !== 'string' || !lexical.trim()) {
throw new ValidationError({
message: tpl(messages.lexicalRequired),
property: 'lexical'
});
}
if (!await lexicalLib.validate(lexical)) {
throw new ValidationError({
message: tpl(messages.invalidLexical),
property: 'lexical'
});
}View on GitHub (pinned to 47d8b0e2ad)
Solutions
- Ensure `frame.data.subject` (or the JSON body `subject`) is a non-empty trimmed string before submitting the request.
- Validate on the client that `subject.trim().length > 0` and surface a form error instead of hitting the API.
- If driving the preview from a post, map the post title into `subject` and default it to a placeholder when the title is blank.
- Confirm the request `Content-Type` is `application/json` so the body parses into `frame.data` correctly.
Example fix
// before
await api.preview({data: {lexical, subject: post.title}}); // post.title is undefined
// after
const subject = (post.title || '').trim();
if (!subject) throw new Error('Cannot preview: post has no title');
await api.preview({data: {lexical, subject}}); Defensive patterns
Strategy: validation
Validate before calling
function validatePreviewPayload({subject, lexical, email} = {}) {
const errors = {};
if (typeof subject !== 'string' || !subject.trim()) errors.subject = 'Subject is required';
if (typeof lexical !== 'string' || !lexical.trim()) errors.lexical = 'Email content is required';
if (email !== undefined && (typeof email !== 'string' || !validator.isEmail(email))) errors.email = 'Invalid email';
return errors;
}
// const errs = validatePreviewPayload(payload); if (Object.keys(errs).length) throw new Error(JSON.stringify(errs)); Type guard
const isNonEmptyString = (v) => typeof v === 'string' && v.trim().length > 0; const hasValidSubject = (p) => isNonEmptyString(p?.subject);
Try / catch
try {
await api.preview({data: {subject, lexical}});
} catch (err) {
if (err.type === 'ValidationError' && err.property === 'subject') showFieldError('subject', err.message);
else throw err;
} Prevention
- Bind the subject input to a required, trimmed form field on the client.
- Run the same non-empty-string guard locally before any preview/send request.
- Unit-test the request builder with empty/whitespace/undefined subjects.
When it happens
Trigger: POSTing to the automation email preview (or send-test-email) endpoint with a body where `subject` is omitted, null, a number/boolean, or an empty/whitespace string. For example `{"lexical": "..."}` with no `subject`, or `{"subject": " "}`.
Common situations: An integration or Zapier-style automation submits a post's title as the subject but the title field is empty on the source post; a frontend form forgets to bind the subject input; the caller sends `subject` as a number (e.g. an ID) by mistake; trailing whitespace from a textarea is the only content.
Related errors
- Email content is required
- The server did not receive a valid email
- Lexical must be a well-formed Lexical document
- Theme is not compatible or contains errors.
- A view with this name already exists
AI-assisted analysis of TryGhost/Ghost@47d8b0e2ad (2026-08-13).
Data as JSON: /api/errors/df453ebb75207c51.
Report an issue: GitHub.