# Error 500 when moving posts

**URL:** https://meta.discourse.org/t/error-500-when-moving-posts/397654
**Category:** Bug
**Created:** [March 4, 2026, 8:14pm UTC](https://meta.discourse.org/t/error-500-when-moving-posts/397654 "2026-03-04T20:14:16Z")
**Posts on this page:** 1
**Showing post:** 8

<div class="post-metadata">

### Author: ![zogstrip](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/zogstrip/32/512781_2.png) [@zogstrip](https://meta.discourse.org/u/zogstrip)
#### Post date: [June 19, 2026, 5:50pm UTC](https://meta.discourse.org/t/error-500-when-moving-posts/397654/8 "2026-06-19T17:50:32Z")

</div>

@here there’s a 55% chance :sweat_smile: this will fix the issue

> <https://github.com/discourse/discourse-activity-pub/pull/319>
>
> \### What
> 
> Moving one or more posts into a \`full\_topic\` topic could raise
> \`Active…Record::RecordNotUnique\` and surface to the user as an HTTP 500 — from
> core's \`TopicsController#move\_posts\`, which only rescues \`RecordInvalid\` /
> \`RecordNotSaved\`, so anything else becomes a 500.
> 
> Reported on Meta: https://meta.discourse.org/t/error-500-when-moving-posts/397654
> 
> \### Why
> 
> ActivityPub records are hidden once tombstoned, via \`IdentifierValidations\`'
> \`default\_scope { where.not(ap\_type: Tombstone.type) }\`. The row still exists,
> though, and still occupies the unique \`(model\_type, model\_id)\` index
> (\`unique\_activity\_pub\_collection\_models\`).
> 
> The \`:first\_post\_moved\` / \`:post\_moved\` handlers check
> \`!topic.activity\_pub\_object\` — which the default scope reports as \`nil\` for a
> tombstoned collection — and call \`create\_activity\_pub\_collection!\`, which
> blindly inserts a second collection for the same topic and collides on the
> unique index.
> 
> It's data-dependent (the destination topic's collection must have been
> tombstoned previously, e.g. via a delete/restore cycle), which matches the
> intermittent, "no visible preconditions" reports.
> 
> \### How
> 
> \`create\_activity\_pub\_collection!\` now looks the collection up \`unscoped\`,
> restores it when tombstoned, and reuses it instead of inserting a duplicate.
> This makes the method idempotent for all of its callers, and preserves the
> collection's \`ap\_id\` (its federation identity) rather than orphaning it.
> 
> \### Tests
> 
> \- Adds a regression test for moving posts into a topic whose collection was
> tombstoned.
> \- A second commit simplifies the \`move\_posts\` topic specs — collapsing the
> per-scenario example fan-out into one example each, with \`:aggregate\_failures\`
> on the group. Same coverage, 38 → 14 examples, roughly half the runtime.

---

_[View the full topic](https://meta.discourse.org/t/error-500-when-moving-posts/397654)._
