TryGhost/Ghost · error · ValidationError

The body of a comment cannot be empty

Error message

The body of a comment cannot be empty

What it means

A ValidationError raised in the Comment model's `onSaving` hook after the raw HTML is passed through `sanitizeHtml` and trimmed. If the sanitized result is empty, the comment had no permitted content left after stripping disallowed tags/attributes. This prevents storing comments that consist solely of blocked markup or whitespace.

Source

Thrown at ghost/core/core/server/models/comment.js:160

            const html = trimParagraphs(
                sanitizeHtml(this.get('html'), {
                    allowedTags: ['p', 'br', 'a', 'blockquote'],
                    allowedAttributes: {
                        a: ['href', 'target', 'rel']
                    },
                    selfClosing: ['br'],
                    // Enforce _blank and safe URLs
                    transformTags: {
                        a: sanitizeHtml.simpleTransform('a', {
                            target: '_blank',
                            rel: 'ugc noopener noreferrer nofollow'
                        })
                    }
                })
            ).trim();

            if (html.length === 0) {
                throw new ValidationError({
                    message: tpl(messages.emptyComment)
                });
            }
            this.set('html', html);
        }
    },

    orderAttributes: function orderAttributes() {
        let keys = ghostBookshelf.Model.prototype.orderAttributes.call(this, arguments);
        keys.push('count__likes');
        keys.push('count__net_score');
        keys.push('count__reports');
        return keys;
    },

    onCreated: function onCreated(model, options) {
        const result = ghostBookshelf.Model.prototype.onCreated.apply(this, arguments);

View on GitHub (pinned to 47d8b0e2ad)

Solutions

  1. Require at least one non-whitespace text character in the comment body on the client before posting.
  2. Strip HTML server-side in your own code and reject if no visible text remains.
  3. Review what tags the comment sanitizer currently allows and ensure the user's content uses allowed markup.
  4. If embedding media, use the supported comment feature set rather than raw disallowed tags.

Example fix

// before
await api.comments.add({html: '<br>'});

// after
const body = '<p>Great post, thanks!</p>';
if (!body.replace(/<[^>]*>/g, '').trim()) throw new Error('Comment has no text');
await api.comments.add({html: body});
Defensive patterns

Strategy: validation

Validate before calling

function hasCommentText(html) {
  const text = String(html || '').replace(/<[^>]*>/g, '').trim();
  return text.length > 0;
}
// if (!hasCommentText(body)) reject('Comment body is empty');

Type guard

const hasVisibleText = (html) => /<[a-z0-9]+[^>]*>(.*?\S.*?)<\/[a-z0-9]+>|\S/i.test(String(html || '')) && String(html || '').replace(/<[^>]*>/g, '').trim().length > 0;

Try / catch

try {
  await api.comments.add({html: body});
} catch (err) {
  if (err.type === 'ValidationError' && /cannot be empty/i.test(err.message)) notifyUser('Write something first');
  else throw err;
}

Prevention

When it happens

Trigger: Posting/replying a comment whose body is only whitespace, only disallowed tags (e.g. `<script>`, `<iframe>`, an unknown tag stripped by the allowlist), or markup whose allowed subset reduces to nothing (e.g. a bare `<br>` with no text). Editing an existing comment to such content also triggers it.

Common situations: A spam bot submits a payload of only disallowed tags; a user pastes only an image/embed that the comment sanitizer strips; a client sends an empty `<p></p>`; the allowlist is tightened in a Ghost version and previously-accepted markup now sanitizes to empty.

Related errors


AI-assisted analysis of TryGhost/Ghost@47d8b0e2ad (2026-08-13). Data as JSON: /api/errors/20f738e157c3355d. Report an issue: GitHub.