majorwiki/05-troubleshooting/security/castopod-broadcast-not-on-mastodon.md
MajorLinux 7c566cda50 Add: diagnosing Castopod posts that don't appear on Mastodon
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>
2026-05-10 00:05:18 -04:00

7.7 KiB

title domain category tags status created updated
Castopod Posts Don't Appear on Mastodon — Diagnosing the Federation Path troubleshooting security
castopod
mastodon
fediverse
activitypub
federation
notifications
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 (@you in 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:

  1. 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.
  2. @-mention in the post. Have Castopod include @you@yourdomain.tld in 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.)
  3. 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_activities row, 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 inbox
    

    Expect a POST /users/<them>/inbox HTTP/2.0 202 from the Castopod IP shortly after published_at. No POST = Castopod didn't deliver despite claiming status='delivered' (rare; check Castopod's HTTP signing config and any outbound firewall on the Castopod host).

  • Check Sidekiq on Mastodon for ActivityPub::ProcessingWorker failures 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: Create activities go to actors in to/cc/bcc/audience; for public posts that resolves to the actor's followers collection.
  • Mastodon notification types: app/models/notification.rbTYPES constant
  • Castopod fediverse module: modules/Fediverse/Commands/Broadcast.php (the per-minute task) and modules/Fediverse/Models/ActivityModel.php (queue model)
  • Related: Castopod: Stale Federated Avatar URLs After Remote Profile Updates — sister article, also Castopod fediverse module