Walks the four-step diagnostic chain (post created → activity delivered → follower exists → notification semantics) for the common confusion where a Castopod admin's auto-broadcast "doesn't show up" on a Mastodon account they expected. Most cases are not federation bugs but the difference between favouriting/boosting (no follow required) and following + the fact that Mastodon notifications fire only for mentions/follows/favs/ boosts/etc., not for new posts from people you follow. Documents the bell icon and `@`-mention escape hatches. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7.7 KiB
| title | domain | category | tags | status | created | updated | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Castopod Posts Don't Appear on Mastodon — Diagnosing the Federation Path | troubleshooting | security |
|
published | 2026-05-10 | 2026-05-10 |
Castopod Posts Don't Appear on Mastodon — Diagnosing the Federation Path
🛑 Problem
You publish a podcast episode (or a standalone post) on Castopod. The Castopod admin shows it went out fine. But on the Mastodon account that you expected to see it from — your own personal account, an account that follows your podcast, a colleague's — the post never shows up. Or it shows up in the home timeline but the notification bell never rings.
Three different failure modes hide behind "I didn't get the post." This article walks the diagnostic chain that distinguishes them.
🔬 The four checks, in order
Run these in sequence. The first one that fails tells you what's actually wrong.
Check 1 — Did Castopod create the post?
On the Castopod host:
mysql -u $CP_DB_USER -p$CP_DB_PASS $CP_DB_NAME --binary-as-hex -e "
SELECT HEX(id), actor_id, LEFT(message,80), episode_id, published_at, created_at
FROM cp_fediverse_posts
ORDER BY created_at DESC LIMIT 5
"
If your post isn't here at all, Castopod didn't generate it. That's a Castopod-side bug — check writable/logs/log-<date>.log, verify the per-minute task scheduler is firing (php spark tasks:list should show Last Run for fediverse-broadcast), and confirm the cron exists:
sudo crontab -u www-data -l | grep tasks:run
# expect: * * * * * php /var/www/html/castopod/spark tasks:run >> /dev/null 2>&1
Check 2 — Did Castopod queue and deliver the activity?
mysql -u $CP_DB_USER -p$CP_DB_PASS $CP_DB_NAME --binary-as-hex -e "
SELECT HEX(id), actor_id, type, status, scheduled_at, created_at
FROM cp_fediverse_activities
WHERE type='Create'
ORDER BY created_at DESC LIMIT 10
"
The status column tells you everything:
| Status | Meaning |
|---|---|
queued |
Sitting in the queue, broadcast task hasn't run yet (or is bogged down) |
processing |
In-flight |
delivered |
All follower inboxes returned 2xx |
failed |
One or more inbox POSTs returned non-2xx, gave up after retries |
If status='delivered', Castopod has done its job — and yet someone says they didn't see the post. Move to Check 3.
Check 3 — Are they actually a follower?
The single most common cause of "I didn't see it." Federation only delivers Create activities to followers (and to anyone explicitly mentioned). Interacting with a post (favourite, boost) does NOT establish a follow relationship.
On the Castopod host:
mysql -u $CP_DB_USER -p$CP_DB_PASS $CP_DB_NAME -e "
SELECT a.username, a.domain, f.created_at
FROM cp_fediverse_follows f
JOIN cp_fediverse_actors a ON a.id = f.actor_id
ORDER BY f.created_at DESC
"
cp_fediverse_follows.actor_id is the follower (remote actor); target_actor_id is your local podcast actor. If the user's username@domain isn't in this list, they don't follow your podcast, and the Create activity was never sent to their inbox.
Cross-check from the Mastodon side (if you control both):
sudo -u postgres psql mastodon_production -t -A -c "
SELECT a.username, a.domain
FROM follows f
JOIN accounts a ON a.id = f.target_account_id
WHERE f.account_id = <mastodon-account-id>
AND a.domain = '<your-castopod-domain>'
"
Empty result on both sides = they're not following. Resolution: have them search @yourpodcast@yourdomain.tld in their Mastodon and click Follow.
A subtler corner of this check: accounts WHERE domain='<your-castopod-domain>' returning 0 rows on the Mastodon side means Mastodon has never even webfingered your podcast actor. The user may have thought they followed at some point, but it never went through (e.g., they typed the handle wrong, or the follow request errored).
Check 4 — Is "didn't see it" a notification problem, not a delivery problem?
Even after a successful follow, the post lands in the home timeline by default. Mastodon notifications (the bell icon, the unread badge) fire for a specific list of activity types — and "new post from someone I follow" isn't one of them. Notifications fire for:
- Mentions (
@youin the post body) - Follows (someone follows you)
- Favourites of your posts
- Boosts of your posts
- Polls ending
- Status edits (post you favourited was edited)
- Admin alerts
So even with delivery working perfectly and the follow in place, "I didn't get a notification on my account" is the expected state for a regular podcast post. Three ways to make notifications happen:
- Bell icon on the followed profile. Mastodon UI: open the followed account's profile → click the bell. Enables per-account post notifications. Now every new post from that account raises a notification.
@-mention in the post. Have Castopod include@you@yourdomain.tldin the post text. Mention activities always raise notifications regardless of follow/bell state. (You may not control the post text on someone else's Castopod, but you control your own.)- Cross-post via a different actor. If you also run a Mastodon account for the show, post manually from there and
@-mention the audience accounts you want to page.
🧪 Worked example
A real case: someone running a podcast on Castopod 2.0.0-next.4 expected a new episode's auto-post to appear on their personal Mastodon. It didn't.
- Check 1 → post present in
cp_fediverse_posts, episode_id correct ✓ - Check 2 → matching
cp_fediverse_activitiesrow,type='Create',status='delivered'✓ - Check 3 → 8 followers in
cp_fediverse_follows, none from the personal Mastodon's domain ✗
Outcome: the user wasn't following their own podcast. They had been favouriting and boosting its posts (which doesn't require following), and assumed those interactions implied a follow. Resolution: search-and-follow from the personal Mastodon. After the follow propagated, future broadcasts arrived as expected.
The post itself never raised a notification (only landed in home timeline). They later enabled the bell icon on the podcast profile and started getting notified on new episodes.
🧭 When this isn't the answer
If Check 3 shows the person IS a follower but they still didn't receive the post:
-
Check their inbox if you have access: Mastodon nginx access log:
sudo grep '<castopod-ip-or-domain>' /var/log/nginx/access.log | grep inboxExpect a
POST /users/<them>/inbox HTTP/2.0 202from the Castopod IP shortly afterpublished_at. No POST = Castopod didn't deliver despite claimingstatus='delivered'(rare; check Castopod's HTTP signing config and any outbound firewall on the Castopod host). -
Check Sidekiq on Mastodon for
ActivityPub::ProcessingWorkerfailures around the activity timestamp. -
Check domain blocks:
SELECT * FROM domain_blocks WHERE domain = '<castopod-domain>'on Mastodon. A silenced or suspended domain on either end would explain everything.
📚 References
- ActivityPub spec — Delivery semantics:
Createactivities go to actors into/cc/bcc/audience; for public posts that resolves to the actor's followers collection. - Mastodon notification types:
app/models/notification.rb—TYPESconstant - Castopod fediverse module:
modules/Fediverse/Commands/Broadcast.php(the per-minute task) andmodules/Fediverse/Models/ActivityModel.php(queue model) - Related: Castopod: Stale Federated Avatar URLs After Remote Profile Updates — sister article, also Castopod fediverse module