{"record":{"id":"d7b47bbacf33f58a","repo":"TryGhost/Ghost","slug":"subject-is-required","errorCode":null,"errorMessage":"Subject is required","messagePattern":"Subject is required","errorType":"validation","errorClass":"ValidationError","httpStatus":422,"severity":"error","filePath":"ghost/core/core/server/api/endpoints/utils/validators/input/automated_emails.js","lineNumber":78,"sourceCode":"    }\n\n    return Promise.resolve();\n};\n\nconst validateOptionalStringField = (value, errorMessage) => {\n    if (value !== undefined && value !== null && typeof value !== 'string') {\n        throw new ValidationError({\n            message: errorMessage\n        });\n    }\n};\n\nconst validatePreviewData = (frame) => {\n    const subject = frame.data.subject;\n    const lexical = frame.data.lexical;\n\n    if (typeof subject !== 'string' || !subject.trim()) {\n        throw new ValidationError({\n            message: tpl(messages.subjectRequired),\n            property: 'subject'\n        });\n    }\n\n    if (typeof lexical !== 'string' || !lexical.trim()) {\n        throw new ValidationError({\n            message: tpl(messages.lexicalRequired),\n            property: 'lexical'\n        });\n    }\n\n    try {\n        JSON.parse(lexical);\n    } catch (e) {\n        throw new ValidationError({\n            message: tpl(messages.invalidLexical),\n            property: 'lexical'","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/TryGhost/Ghost/blob/47d8b0e2ad2fd4757d3bc45f46c3ac165ff8a1fe/ghost/core/core/server/api/endpoints/utils/validators/input/automated_emails.js#L60-L96","documentation":"Thrown by `validatePreviewData` (used by the automated-emails `preview` and `sendTestEmail` validators) when `frame.data.subject` is not a non-empty trimmed string. Ghost requires a subject before rendering/sending an email preview, so a missing or blank subject yields a 422 ValidationError on the `subject` property.","triggerScenarios":"A POST to the email preview/test endpoint omits `subject`, sends it as a non-string type, or sends a whitespace-only string.","commonSituations":"Frontend sends the preview request before the subject field is filled; JSON payload drops the subject key; subject is sent as `null` or an empty string; automated client forgetting required fields.","solutions":["Ensure the request body includes `subject` as a non-empty string.","Trim and validate the subject client-side before submitting.","Confirm the JSON serialization includes the subject key."],"exampleFix":"// before\nawait api.emailPreview.send({data: {lexical, email: 'a@b.com'}}); // subject missing\n\n// after\nawait api.emailPreview.send({data: {subject: 'Welcome', lexical, email: 'a@b.com'}});","handlingStrategy":"validation","validationCode":"function isValidSubject(s: unknown): s is string {\n    return typeof s === 'string' && s.trim().length > 0;\n}\nif (!isValidSubject(payload.subject)) {\n    throw new Error('subject must be a non-empty string');\n}","typeGuard":"function isNonEmptyString(v: unknown): v is string {\n    return typeof v === 'string' && v.trim().length > 0;\n}","tryCatchPattern":null,"preventionTips":["Always include a non-empty `subject` in preview/test-email payloads.","Validate the subject client-side before submission.","Confirm the JSON payload includes the `subject` key."],"tags":["api","validation","email","automated-emails","preview"],"backgroundTag":null,"analyzedSha":"47d8b0e2ad2fd4757d3bc45f46c3ac165ff8a1fe","analyzedAt":"2026-08-13T01:25:26.651Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}