TryGhost/Ghost · error · ValidationError
Token is required
Error message
Token is required
What it means
Thrown by the `verifySenderUpdate` validator when `frame.data.token` is not a non-empty trimmed string. The sender-update verification flow requires the token from the confirmation email; without it Ghost cannot verify the sender change and returns a 422 ValidationError.
Source
Thrown at ghost/core/core/server/api/endpoints/utils/validators/input/automated_emails.js:119
module.exports = {
async add(apiConfig, frame) {
await validateAutomatedEmail(frame);
},
async edit(apiConfig, frame) {
await validateAutomatedEmail(frame);
},
editSenders(apiConfig, frame) {
const senderName = frame.data.sender_name;
const senderEmail = frame.data.sender_email;
const senderReplyTo = frame.data.sender_reply_to;
validateOptionalStringField(senderName, 'Sender name must be a string');
validateOptionalStringField(senderEmail, 'Sender email must be a string');
validateOptionalStringField(senderReplyTo, 'Reply-to email must be a string');
},
verifySenderUpdate(apiConfig, frame) {
if (typeof frame.data.token !== 'string' || !frame.data.token.trim()) {
throw new ValidationError({
message: tpl(messages.tokenRequired)
});
}
},
preview(apiConfig, frame) {
validatePreviewData(frame);
},
sendTestEmail(apiConfig, frame) {
const email = frame.data.email;
if (typeof email !== 'string' || !validator.isEmail(email)) {
throw new ValidationError({
message: tpl(messages.invalidEmailReceived)
});
}
validatePreviewData(frame);
}View on GitHub (pinned to 47d8b0e2ad)
Solutions
- Extract the `token` query parameter from the verification email/link and include it in the request body.
- Confirm the token is a non-empty string before submitting.
- Re-request the sender update email if the token was lost.
Example fix
// before
await api.email.verifySenderUpdate({data: {}}); // no token
// after
await api.email.verifySenderUpdate({data: {token: urlSearchParams.get('token')}}); Defensive patterns
Strategy: validation
Validate before calling
function isNonEmptyToken(v: unknown): v is string {
return typeof v === 'string' && v.trim().length > 0;
}
if (!isNonEmptyToken(payload.token)) {
throw new Error('token is required');
} Type guard
function isNonEmptyString(v: unknown): v is string {
return typeof v === 'string' && v.trim().length > 0;
} Prevention
- Extract the `token` from the verification email link before calling the endpoint.
- Confirm the token has not been stripped from the URL/payload.
- Re-request the sender-update email if the token is lost.
When it happens
Trigger: A request to the verify-sender-update endpoint omits `token`, sends it as a non-string type, or sends whitespace only.
Common situations: User clicked a verification link whose token query param was stripped; frontend forwarded the request without extracting the token from the URL; token expired/cleared; payload key misspelled.
Related errors
- Subject is required
- Email content is required
- The server did not receive a valid email
- Lexical must be a valid JSON string
- Cannot disconnect Stripe whilst you have active subscription
AI-assisted analysis of TryGhost/Ghost@47d8b0e2ad (2026-08-13).
Data as JSON: /api/errors/f976e55e30275c00.
Report an issue: GitHub.