Scalar tags parameter accepted into review queue causes HTTP 500 on approval

AI-generated summary

This bug report details an issue where a scalar string value for the tags parameter (e.g., "macos") is accepted into the review queue via POST /posts, causing an HTTP 500 error when a moderator attempts to approve the post. scavin explains that while clients should send arrays, the system fails to validate or normalize scalar strings during submission. The error occurs because DiscourseTagging.tags_for_saving attempts to perform array subtraction on a string, raising a NoMethodError. The root cause lies in ReviewableQueuedPost#create_options, which only converts tags if they are already an Array. The expected behavior is to either reject scalar inputs with a clear validation error or normalize them appropriately. A workaround involves manually editing the reviewable payload to convert the string into an array of tag objects. sam has provided a fix in PR #44990 to prevent this invalid input from being accepted.

Approving a queued topic on our self-hosted site failed with HTTP 500 because the queued record contained payload.tags = "macos" (a string). The malformed value had already been accepted by POST /posts.

I understand that clients should send an array of tags. The issue I am reporting is that an invalid scalar can be accepted into the review queue and only fail later, when a moderator approves the post.

Version: 2026.10.0-latest, commit 3f2bf92368c78a7fa9a755f3d046adf35dd4459b.

Evidence from the incident

The post required approval because of approve_post_count.

At 2026-10-22 13:37:52 UTC, the original Rails request parameters already contained:

"tags" => "macos"

The request was POST /posts and the corresponding access log recorded HTTP 200. The submitted parameter names were title, raw, category, and tags.

Reading the pending reviewable confirmed:

{
  "type": "ReviewableQueuedPost",
  "status": 0,
  "version": 0,
  "topic_id": null,
  "payload": {
    "tags": "macos"
  }
}

This is a relevant-field excerpt, with the title, body, and user information omitted. The review UI displayed the tag as five separate letters: m, a, c, o, s.

Clicking Approve produced this exception (five grouped occurrences in the logs):

NoMethodError (undefined method '-' for an instance of String)
lib/discourse_tagging.rb:932:in 'DiscourseTagging.tags_for_saving'
lib/discourse_tagging.rb:43:in 'DiscourseTagging.tag_topic_by_names'
lib/discourse_tagging.rb:30:in 'DiscourseTagging.tag_topic'
lib/topic_creator.rb:228:in 'TopicCreator#setup_tags'
lib/topic_creator.rb:60:in 'TopicCreator#create'
lib/post_creator.rb:519:in 'PostCreator#create_topic'
lib/post_creator.rb:209:in 'block in PostCreator#create'
lib/post_creator.rb:419:in 'block in PostCreator#transaction'
lib/post_creator.rb:419:in 'PostCreator#transaction'
lib/post_creator.rb:207:in 'PostCreator#create'
app/models/reviewable_queued_post.rb:110:in 'ReviewableQueuedPost#perform_approve_post'
app/models/reviewable.rb:433:in 'Kernel#public_send'
app/models/reviewable.rb:433:in 'block in Reviewable#perform'
app/models/reviewable.rb:431:in 'Reviewable#perform'
app/controllers/reviewables_controller.rb:287:in 'ReviewablesController#perform'

Relevant code

These are the code paths checked in the running container at the commit above:

Expected behavior

Reject a scalar tags parameter with a clear validation error before creating the reviewable, or normalize it if that is the intended compatibility behavior. An existing malformed reviewable should also fail gracefully instead of causing an unhandled 500 during moderation.

Workaround and limits of this report

Editing the reviewable, removing the old tag, selecting the existing macos tag, and saving changed payload.tags into an array of tag objects. Readback confirmed version 1, still pending, and the UI showed one tag again. I have not retried approval after that change.

The original submitter’s client is unknown. This report does not establish that the native composer generates scalar tags. It is based on the actual request, stored reviewable, exception, and inspected code; I have not separately reproduced it on a clean installation.

For a development reproduction, the path to test is: require approval for a non-staff user’s post, submit POST /posts with a scalar tags: "macos" and otherwise valid fields, then approve the resulting queued post as an administrator.

There is an older API discussion with the same String subtraction exception. This report focuses on the invalid value being accepted into the review queue and breaking approval later.

honestly not sure where this is coming from, but here is a fix to ban it.

1 Like