Troubleshooting Mastodon Backfeed and Stale Webmentions

Category: Development

Tags: indieweb, mastodon, webmentions


Automating syndication was the easy part. Getting reaction backfeed and cleanup right — so that likes, reposts, and replies from Mastodon appear on the canonical post and disappear when the source is deleted — needed considerably more care. This is the practical checklist that emerged from debugging real failures.

The setup

  • Canonical site: Astro 6 static build at adrian-altner.de.
  • Bridge: Bridgy Fed, mapping Mastodon interactions to canonical URLs via u-syndication.
  • Store: webmention.io, queried at build and from the client for live updates.

Outside the authorized scopes

Problem: Mastodon returns:

{"error":"This action is outside the authorized scopes"}

The access token is missing required permissions.

Implementation: for script-based posting, issue a token with at least:

  • write:statuses
  • write:media

Also strip unnecessary API calls that would need extra scopes. Removing a pre-flight verify_credentials from the post flow eliminated a class of scope failures that had nothing to do with posting.

Backfeed not appearing on Bridgy

Problem: a common trap — interacting with the syndicated Mastodon post before the site is redeployed with the matching u-syndication link. If Bridgy can’t map the social interaction back to the canonical page URL, it shows nothing.

Implementation: fix order matters.

  1. Deploy first so “Shared on Mastodon” is live on the page.
  2. Use Bridgy’s Poll now / Crawl now.
  3. If still missing, trigger Resend for post.
  4. Retry the interaction.

Solution: the u-syndication link has to exist on the canonical page at the moment Bridgy crawls. Any sequence that reverses that ends in silent data loss — the reactions happened, but Bridgy had nowhere to route them.

Canonical URL mismatch (trailing slash)

webmention.io target matching is exact. .../hello-world and .../hello-world/ are different targets.

When debugging, always test with the canonical URL as it appears on the page — including trailing slash — otherwise you can easily read an empty result and chase the wrong bug for an hour.

429 Too many requests on media uploads

Problem: large backfills saturate media API limits fast.

Implementation: the syndication script now retries media uploads with backoff and honours Retry-After when the server sends it. Status posting continues even if a media upload ultimately fails, so the text post goes out and backfill progress isn’t blocked by images.

Deleted likes/reposts still visible

The most annoying failure mode. Deletions don’t always propagate cleanly through every layer — webmention.io can still hold the old reaction record, and the source URL may still return HTTP 200 even when the interaction itself is gone upstream.

Implementation: source re-validation at interaction level, not just URL existence:

  • Mastodon — validate favorited-by / reblogged-by against the status’s interaction APIs.
  • Bluesky — validate liked_by / reposted_by against the public API lists.
  • Replies — validate source post existence directly via the platform APIs.

Solution: if the upstream interaction or source post is gone, it’s filtered out automatically at render time — no manual dashboard surgery required.

Client refresh not removing stale UI

Problem: even with correct filtering server-side, the UI can stay stale if the client refresh only handles additions.

Implementation: the webmentions component now tracks the current count and re-renders on both directions:

  • new mentions added
  • existing mentions removed

Solution: deletions become visible without having to manually prune in the webmention.io dashboard.

A practical debugging order

When something looks wrong, this order cuts through the noise:

  1. Verify the canonical target URL — including trailing slash.
  2. Inspect filtered local endpoint output.
  3. Check source interaction / post existence upstream.
  4. Trigger Bridgy poll / crawl.
  5. Only then touch manual dashboard deletion.

Most “it still shows” issues are one of those five, not a rendering bug.

What to take away

  • Token scopes are the first thing to check. write:statuses and write:media are the minimum; cut any pre-flight calls that need more.
  • Deploy before interacting. Bridgy needs the u-syndication link on the canonical page at crawl time, not later.
  • Trailing slashes are load-bearing. Treat them as part of the identifier everywhere — webmention.io, state files, component queries.
  • Re-validate upstream interactions, not just URLs. A source URL can return 200 long after the like itself is gone — only the interaction API tells the truth.
  • Client refresh must handle both directions. Additions and removals, otherwise deleted reactions linger in the UI forever.