Visual bug in review queue notification

AI-generated summary

small-lovely-cat reported a visual bug in the review queue notification system occurring when a post awaiting approval has its topic removed. In this scenario, the notification incorrectly displays “new post in [missing %{title} value]” instead of indicating the topic is deleted. Additionally, the user noted that while staff members see the correct topic title in the queue, category moderators see an empty title, making it difficult to locate the original topic. To support the report, the user provided screenshots and detailed API responses from both staff and category moderator perspectives, highlighting discrepancies in the target_type and topic_id fields. awesomerobot acknowledged the detailed report and confirmed that a fix is currently in progress via this pull request.

For these step:

  • A post is waiting for approval
  • Remove the topic of the post
  • Then the post in queue will have:“new post in [missing %{title} value]” as the notification.

image

Maybe the notification should be new post in a deleted topic?


  • Also, for category moderators, the topic title for the post in the review queue will be empty (for staff, it is alright), which make finding the original topic difficult.

[staff]

[category moderator]

Something that can help:

review api result

GET /review [staff]

{
    "reviewables": [
        {
            "id": 2,
            "type": "ReviewableQueuedPost",
            "type_source": "core",
            "target_type": null,
            "target_id": null,
            "category_id": 5,
            "created_at": "2026-01-31T08:42:00.149Z",
            "can_edit": true,
            "score": 6.0,
            "version": 1,
            "target_created_by_trust_level": 1,
            "created_from_flag": false,
            "status": 0,
            "removed_topic_id": null,
            "payload": {
                "raw": "This topic is for test.",
                "title": "This topic is for test.",
                "is_poll": true,
                "typing_duration_msecs": 4400,
                "composer_open_duration_msecs": 28333,
                "tags": null
            },
            "created_by_id": -1,
            "target_created_by_id": 2,
            "topic_id": null,
            "editable_fields": [
                {
                    "id": "payload.title",
                    "type": "text"
                },
                {
                    "id": "category_id",
                    "type": "category"
                },
                {
                    "id": "payload.tags",
                    "type": "tags"
                },
                {
                    "id": "payload.raw",
                    "type": "editor"
                }
            ],
            "reviewable_score_ids": [
                2
            ],
            "bundled_action_ids": [
                "approve_post",
                "2-reject-post"
            ],
            "reviewable_note_ids": [],
            "reviewable_history_ids": [
                2,
                3
            ],
            "claimed_by_id": null
        },
        {
            "id": 1,
            "type": "ReviewableQueuedPost",
            "type_source": "core",
            "topic_id": 7,
            "topic_url": "https://probable-spork-p6ppvj5vjp6cr7xj-4200.app.github.dev/t/this-is-a-general-topic/7",
            "target_type": null,
            "target_id": null,
            "target_url": "https://probable-spork-p6ppvj5vjp6cr7xj-4200.app.github.dev/t/this-is-a-general-topic/7",
            "topic_tags": [],
            "category_id": 5,
            "created_at": "2026-01-31T06:21:47.526Z",
            "can_edit": true,
            "score": 6.0,
            "version": 0,
            "target_created_by_trust_level": 1,
            "created_from_flag": false,
            "status": 0,
            "payload": {
                "raw": "This is for test.\n\nThis is for test.\n\nThis is for test.",
                "is_poll": true,
                "typing_duration_msecs": 4200,
                "composer_open_duration_msecs": 21460,
                "tags": null
            },
            "created_by_id": -1,
            "target_created_by_id": 2,
            "editable_fields": [
                {
                    "id": "payload.raw",
                    "type": "editor"
                }
            ],
            "reviewable_score_ids": [
                1
            ],
            "bundled_action_ids": [
                "approve_post",
                "1-reject-post"
            ],
            "reviewable_note_ids": [],
            "reviewable_history_ids": [
                1
            ],
            "claimed_by_id": null
        }
    ],
    "meta": {
        "ids": null,
        "status": "pending",
        "category_id": null,
        "topic_id": null,
        "additional_filters": {},
        "priority": "low",
        "username": null,
        "reviewed_by": null,
        "claimed_by": null,
        "from_date": null,
        "to_date": null,
        "type": null,
        "sort_order": "score",
        "flagged_by": null,
        "score_type": null,
        "total_rows_reviewables": 2,
        "types": {
            "created_by": "user",
            "target_created_by": "user",
            "target_deleted_by": "user",
            "reviewed_by": "user",
            "claimed_by": "claimed_by"
        },
        "reviewable_types": [
            "ReviewableFlaggedPost",
            "ReviewableQueuedPost",
            "ReviewableUser",
            "ReviewablePost",
            "Chat::ReviewableMessage"
        ],
        "unknown_reviewable_types_and_sources": [],
        "score_types": [
            {
                "id": 3,
                "name": "Off-Topic"
            },
            {
                "id": 4,
                "name": "Inappropriate"
            },
            {
                "id": 8,
                "name": "Spam"
            },
            {
                "id": 10,
                "name": "Illegal"
            },
            {
                "id": 7,
                "name": "Something Else"
            },
            {
                "id": 9,
                "name": "Needs Approval"
            }
        ],
        "reviewable_count": 2,
        "unseen_reviewable_count": 1
    },
    "users": [
        {
            "id": -1,
            "username": "system",
            "name": "system",
            "avatar_template": "/images/discourse-logo-sketch-small.png",
            "custom_fields": {}
        },
        {
            "id": 2,
            "username": "user2",
            "name": null,
            "avatar_template": "/letter_avatar_proxy/v4/letter/u/ecb155/{size}.png",
            "can_delete_all_posts": true,
            "can_be_deleted": true,
            "post_count": 0,
            "topic_count": 0,
            "ip_address": "127.0.0.1",
            "email": "test1@test.com",
            "custom_fields": {},
            "flags_agreed": 0,
            "flags_disagreed": 0,
            "flags_ignored": 0,
            "created_at": "2026-01-31T06:19:12.132Z",
            "trust_level": 1,
            "silenced_count": 0,
            "suspended_count": 0,
            "rejected_posts_count": 0
        },
        {
            "id": 1,
            "username": "cattie",
            "name": null,
            "avatar_template": "/letter_avatar_proxy/v4/letter/c/ee59a6/{size}.png"
        },
        {
            "id": -1,
            "username": "system",
            "name": "system",
            "avatar_template": "/images/discourse-logo-sketch-small.png",
            "custom_fields": {}
        },
        {
            "id": 2,
            "username": "user2",
            "name": null,
            "avatar_template": "/letter_avatar_proxy/v4/letter/u/ecb155/{size}.png",
            "can_delete_all_posts": true,
            "can_be_deleted": true,
            "post_count": 0,
            "topic_count": 0,
            "ip_address": "127.0.0.1",
            "email": "test1@test.com",
            "custom_fields": {},
            "flags_agreed": 0,
            "flags_disagreed": 0,
            "flags_ignored": 0,
            "created_at": "2026-01-31T06:19:12.132Z",
            "trust_level": 1,
            "silenced_count": 0,
            "suspended_count": 0,
            "rejected_posts_count": 0
        }
    ],
    "topics": [
        {
            "fancy_title": "This is a general topic",
            "id": 7,
            "title": "This is a general topic",
            "slug": "this-is-a-general-topic",
            "posts_count": 0,
            "reply_count": 0,
            "highest_post_number": 0,
            "image_url": null,
            "created_at": "2026-01-31T06:21:19.672Z",
            "last_posted_at": null,
            "bumped": true,
            "bumped_at": "2026-01-31T06:21:19.836Z",
            "archetype": "regular",
            "unseen": true,
            "pinned": false,
            "unpinned": null,
            "visible": true,
            "closed": false,
            "archived": false,
            "bookmarked": null,
            "liked": null,
            "has_accepted_answer": false
        }
    ],
    "reviewable_scores": [
        {
            "id": 2,
            "score": 6.0,
            "agree_stats": {
                "agreed": 0,
                "disagreed": 0,
                "ignored": 0
            },
            "reason": "This post included a Watched Word, the flagged word is: test. Check the <a href=\"https://probable-spork-p6ppvj5vjp6cr7xj-4200.app.github.dev/admin/customize/watched_words\">watched word settings</a> for more.",
            "reason_type": "watched_word",
            "reason_data": [
                "test"
            ],
            "created_at": "2026-01-31T08:42:00.218Z",
            "reviewed_at": null,
            "status": 0,
            "user_id": -1,
            "score_type_id": 9,
            "reviewable_conversation_id": null,
            "reviewed_by_id": null
        },
        {
            "id": 1,
            "score": 6.0,
            "agree_stats": {
                "agreed": 0,
                "disagreed": 0,
                "ignored": 0
            },
            "reason": "This post included a Watched Word, the flagged word is: test. Check the <a href=\"https://probable-spork-p6ppvj5vjp6cr7xj-4200.app.github.dev/admin/customize/watched_words\">watched word settings</a> for more.",
            "reason_type": "watched_word",
            "reason_data": [
                "test"
            ],
            "created_at": "2026-01-31T06:21:47.562Z",
            "reviewed_at": null,
            "status": 0,
            "user_id": -1,
            "score_type_id": 9,
            "reviewable_conversation_id": null,
            "reviewed_by_id": null
        }
    ],
    "score_types": [
        {
            "id": 9,
            "title": "Needs Approval",
            "icon": "flag",
            "type": "needs_approval"
        },
        {
            "id": 9,
            "title": "Needs Approval",
            "icon": "flag",
            "type": "needs_approval"
        }
    ],
    "reviewable_conversations": [],
    "bundled_actions": [
        {
            "id": "approve_post",
            "action_ids": [
                "approve_post"
            ]
        },
        {
            "id": "2-reject-post",
            "label": "No",
            "action_ids": [
                "reject_post",
                "revise_and_reject_post",
                "delete_user",
                "delete_user_block"
            ]
        },
        {
            "id": "1-reject-post",
            "label": "No",
            "action_ids": [
                "reject_post",
                "revise_and_reject_post",
                "delete_user",
                "delete_user_block"
            ]
        }
    ],
    "actions": [
        {
            "id": "approve_post",
            "icon": "check",
            "button_class": null,
            "label": "Yes",
            "server_action": "approve_post",
            "completed_message": "Post approved."
        },
        {
            "id": "reject_post",
            "icon": "xmark",
            "button_class": null,
            "label": "Reject Post",
            "server_action": "reject_post",
            "completed_message": "Post rejected."
        },
        {
            "id": "revise_and_reject_post",
            "icon": "envelope",
            "button_class": null,
            "label": "Request Revision...",
            "server_action": "revise_and_reject_post",
            "completed_message": "Post rejected pending revision."
        },
        {
            "id": "delete_user",
            "icon": "user-xmark",
            "button_class": null,
            "label": "Delete User",
            "description": "Delete user without blocking",
            "server_action": "delete_user",
            "completed_message": null
        },
        {
            "id": "delete_user_block",
            "icon": "ban",
            "button_class": null,
            "label": "Delete and Block User",
            "description": "The user will be deleted, and we'll block their IP and email address.",
            "server_action": "delete_user_block",
            "completed_message": null
        }
    ],
    "reviewable_notes": [],
    "reviewable_histories": [
        {
            "id": 2,
            "created_at": "2026-01-31T08:42:00.159Z",
            "reviewable_history_type": 0,
            "status": 0,
            "created_by_id": -1
        },
        {
            "id": 3,
            "created_at": "2026-01-31T08:42:20.933Z",
            "reviewable_history_type": 2,
            "status": 0,
            "created_by_id": 1
        },
        {
            "id": 1,
            "created_at": "2026-01-31T06:21:47.536Z",
            "reviewable_history_type": 0,
            "status": 0,
            "created_by_id": -1
        }
    ],
    "claimed_bies": [],
    "__rest_serializer": "1"
}

GET /review category moderators:

{
    "reviewables": [
        {
            "id": 2,
            "type": "ReviewableQueuedPost",
            "type_source": "core",
            "target_type": null,
            "target_id": null,
            "category_id": 5,
            "created_at": "2026-01-31T08:42:00.149Z",
            "can_edit": true,
            "score": 6.0,
            "version": 1,
            "target_created_by_trust_level": 1,
            "created_from_flag": false,
            "status": 0,
            "removed_topic_id": null,
            "payload": {
                "raw": "This topic is for test.",
                "title": "This topic is for test.",
                "is_poll": true,
                "typing_duration_msecs": 4400,
                "composer_open_duration_msecs": 28333,
                "tags": null
            },
            "created_by_id": -1,
            "target_created_by_id": 2,
            "topic_id": null,
            "editable_fields": [
                {
                    "id": "payload.title",
                    "type": "text"
                },
                {
                    "id": "payload.tags",
                    "type": "tags"
                },
                {
                    "id": "payload.raw",
                    "type": "editor"
                }
            ],
            "reviewable_score_ids": [
                2
            ],
            "bundled_action_ids": [
                "approve_post",
                "2-reject-post",
                "delete"
            ],
            "reviewable_note_ids": [],
            "reviewable_history_ids": [
                2,
                3
            ],
            "claimed_by_id": null
        },
        {
            "id": 1,
            "type": "ReviewableQueuedPost",
            "type_source": "core",
            "topic_id": null,
            "target_type": null,
            "target_id": null,
            "category_id": 5,
            "created_at": "2026-01-31T06:21:47.526Z",
            "can_edit": true,
            "score": 6.0,
            "version": 0,
            "target_created_by_trust_level": 1,
            "created_from_flag": false,
            "status": 0,
            "removed_topic_id": 7,
            "payload": {
                "raw": "This is for test.\n\nThis is for test.\n\nThis is for test.",
                "is_poll": true,
                "typing_duration_msecs": 4200,
                "composer_open_duration_msecs": 21460,
                "tags": null
            },
            "created_by_id": -1,
            "target_created_by_id": 2,
            "editable_fields": [
                {
                    "id": "payload.raw",
                    "type": "editor"
                }
            ],
            "reviewable_score_ids": [
                1
            ],
            "bundled_action_ids": [
                "approve_post",
                "1-reject-post",
                "delete"
            ],
            "reviewable_note_ids": [],
            "reviewable_history_ids": [
                1
            ],
            "claimed_by_id": null
        }
    ],
    "meta": {
        "ids": null,
        "status": "pending",
        "category_id": null,
        "topic_id": null,
        "additional_filters": {},
        "priority": "low",
        "username": null,
        "reviewed_by": null,
        "claimed_by": null,
        "from_date": null,
        "to_date": null,
        "type": null,
        "sort_order": "score",
        "flagged_by": null,
        "score_type": null,
        "total_rows_reviewables": 2,
        "types": {
            "created_by": "user",
            "target_created_by": "user",
            "target_deleted_by": "user",
            "reviewed_by": "user",
            "claimed_by": "claimed_by"
        },
        "reviewable_types": [
            "ReviewableFlaggedPost",
            "ReviewableQueuedPost",
            "ReviewableUser",
            "ReviewablePost",
            "Chat::ReviewableMessage"
        ],
        "unknown_reviewable_types_and_sources": [],
        "score_types": [
            {
                "id": 3,
                "name": "Off-Topic"
            },
            {
                "id": 4,
                "name": "Inappropriate"
            },
            {
                "id": 8,
                "name": "Spam"
            },
            {
                "id": 10,
                "name": "Illegal"
            },
            {
                "id": 7,
                "name": "Something Else"
            },
            {
                "id": 9,
                "name": "Needs Approval"
            }
        ],
        "reviewable_count": 2,
        "unseen_reviewable_count": 1
    },
    "users": [
        {
            "id": -1,
            "username": "system",
            "name": "system",
            "avatar_template": "/images/discourse-logo-sketch-small.png",
            "custom_fields": {}
        },
        {
            "id": 2,
            "username": "user2",
            "name": null,
            "avatar_template": "/letter_avatar_proxy/v4/letter/u/ecb155/{size}.png",
            "can_delete_all_posts": false,
            "can_be_deleted": true,
            "post_count": 0,
            "topic_count": 0,
            "ip_address": "127.0.0.1",
            "custom_fields": {},
            "flags_agreed": 0,
            "flags_disagreed": 0,
            "flags_ignored": 0,
            "created_at": "2026-01-31T06:19:12.132Z",
            "trust_level": 1,
            "silenced_count": 0,
            "suspended_count": 0,
            "rejected_posts_count": 0
        },
        {
            "id": 1,
            "username": "cattie",
            "name": null,
            "avatar_template": "/letter_avatar_proxy/v4/letter/c/ee59a6/{size}.png"
        },
        {
            "id": -1,
            "username": "system",
            "name": "system",
            "avatar_template": "/images/discourse-logo-sketch-small.png",
            "custom_fields": {}
        },
        {
            "id": 2,
            "username": "user2",
            "name": null,
            "avatar_template": "/letter_avatar_proxy/v4/letter/u/ecb155/{size}.png",
            "can_delete_all_posts": false,
            "can_be_deleted": true,
            "post_count": 0,
            "topic_count": 0,
            "ip_address": "127.0.0.1",
            "custom_fields": {},
            "flags_agreed": 0,
            "flags_disagreed": 0,
            "flags_ignored": 0,
            "created_at": "2026-01-31T06:19:12.132Z",
            "trust_level": 1,
            "silenced_count": 0,
            "suspended_count": 0,
            "rejected_posts_count": 0
        }
    ],
    "topics": [],
    "reviewable_scores": [
        {
            "id": 2,
            "score": 6.0,
            "agree_stats": {
                "agreed": 0,
                "disagreed": 0,
                "ignored": 0
            },
            "reason": "This post included a Watched Word, the flagged word is: test. Check the watched word settings for more.",
            "reason_type": "watched_word",
            "reason_data": [
                "test"
            ],
            "created_at": "2026-01-31T08:42:00.218Z",
            "reviewed_at": null,
            "status": 0,
            "user_id": -1,
            "score_type_id": 9,
            "reviewable_conversation_id": null,
            "reviewed_by_id": null
        },
        {
            "id": 1,
            "score": 6.0,
            "agree_stats": {
                "agreed": 0,
                "disagreed": 0,
                "ignored": 0
            },
            "reason": "This post included a Watched Word, the flagged word is: test. Check the watched word settings for more.",
            "reason_type": "watched_word",
            "reason_data": [
                "test"
            ],
            "created_at": "2026-01-31T06:21:47.562Z",
            "reviewed_at": null,
            "status": 0,
            "user_id": -1,
            "score_type_id": 9,
            "reviewable_conversation_id": null,
            "reviewed_by_id": null
        }
    ],
    "score_types": [
        {
            "id": 9,
            "title": "Needs Approval",
            "icon": "flag",
            "type": "needs_approval"
        },
        {
            "id": 9,
            "title": "Needs Approval",
            "icon": "flag",
            "type": "needs_approval"
        }
    ],
    "reviewable_conversations": [],
    "bundled_actions": [
        {
            "id": "approve_post",
            "action_ids": [
                "approve_post"
            ]
        },
        {
            "id": "2-reject-post",
            "label": "No",
            "action_ids": [
                "reject_post",
                "revise_and_reject_post",
                "delete_user",
                "delete_user_block"
            ]
        },
        {
            "id": "delete",
            "action_ids": [
                "delete"
            ]
        },
        {
            "id": "1-reject-post",
            "label": "No",
            "action_ids": [
                "reject_post",
                "revise_and_reject_post",
                "delete_user",
                "delete_user_block"
            ]
        }
    ],
    "actions": [
        {
            "id": "approve_post",
            "icon": "check",
            "button_class": null,
            "label": "Yes",
            "server_action": "approve_post",
            "completed_message": "Post approved."
        },
        {
            "id": "reject_post",
            "icon": "xmark",
            "button_class": null,
            "label": "Reject Post",
            "server_action": "reject_post",
            "completed_message": "Post rejected."
        },
        {
            "id": "revise_and_reject_post",
            "icon": "envelope",
            "button_class": null,
            "label": "Request Revision...",
            "server_action": "revise_and_reject_post",
            "completed_message": "Post rejected pending revision."
        },
        {
            "id": "delete_user",
            "icon": "user-xmark",
            "button_class": null,
            "label": "Delete User",
            "description": "Delete user without blocking",
            "server_action": "delete_user",
            "completed_message": null
        },
        {
            "id": "delete_user_block",
            "icon": "ban",
            "button_class": null,
            "label": "Delete and Block User",
            "description": "The user will be deleted, and we'll block their IP and email address.",
            "server_action": "delete_user_block",
            "completed_message": null
        },
        {
            "id": "delete",
            "icon": null,
            "button_class": null,
            "label": "Delete",
            "server_action": "delete",
            "completed_message": "Post deleted."
        }
    ],
    "reviewable_notes": [],
    "reviewable_histories": [
        {
            "id": 2,
            "created_at": "2026-01-31T08:42:00.159Z",
            "reviewable_history_type": 0,
            "status": 0,
            "created_by_id": -1
        },
        {
            "id": 3,
            "created_at": "2026-01-31T08:42:20.933Z",
            "reviewable_history_type": 2,
            "status": 0,
            "created_by_id": 1
        },
        {
            "id": 1,
            "created_at": "2026-01-31T06:21:47.536Z",
            "reviewable_history_type": 0,
            "status": 0,
            "created_by_id": -1
        }
    ],
    "claimed_bies": [],
    "__rest_serializer": "1"
}

Seems that under this circumstance, staffs will get the full topic object even if the topic is deleted, while category moderators will only get an empty topic object with deleted_topic_id, and in ember template, since waiting for approval is a has-block object, it doesn’t fell in topic_deleted category, while rendered an empty template.

    {{else if (has-block)}}
      {{yield}}
    {{else}}
      <span class="title-text">
        {{i18n "review.topics.deleted"}}
        <LinkTo
          @route="topic"
          @models={{array "-" @reviewable.removed_topic_id}}
        >{{i18n "review.topics.original"}}</LinkTo>
      </span>
    {{/if}}
2 Likes

Lovely report, thanks! I have a fix in progress

https://github.com/discourse/discourse/pull/37497

2 Likes