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:
- PostsController#create_params calls
params.permit(tags: %i[id name]), but does not use the returned filtered parameters. It then assigns the original value withresult[f] = params[f]. - NewPostManager#enqueue copies
@args[:tags]directly into the reviewable payload. - ReviewableQueuedPost#create_options converts tags only when the value is already an Array, leaving a scalar string unchanged.
- DiscourseTagging.tags_for_saving then evaluates
tags_arg - tag_nameswhen the approving user can create tags, which raises for a string.
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.