Self-heal stale image blob refs on publish#143
Draft
pfefferle wants to merge 6 commits into
Draft
Conversation
When a cached blob CID points at a blob the active PDS no longer holds (account/PDS switch, or orphaned-blob garbage collection on the reference PDS), applyWrites rejects the publish with "Could not find blob". Drop the cached refs for every image the post embeds and retry the publish once so the post lands without manually clearing _atmosphere_blob_ref. Reported at https://wordpress.org/support/topic/backfilled-posts-with-featured-images-fail-400-could-not-find-blob/
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds an automatic recovery path for publish/backfill failures caused by stale cached image blob CIDs (_atmosphere_blob_ref) that no longer exist on the currently connected PDS. On a specific applyWrites 400 “Could not find blob” error, Publisher now clears cached blob refs for all images the post may embed and retries the publish once so images are re-uploaded to the active PDS.
Changes:
- Added a one-time retry in
Publisher::publish_post()that self-heals “Could not find blob” failures by clearing cached image blob refs before retrying. - Introduced transformer helpers (
forget_*+embedded_image_attachment_ids()) to centralize “which attachments can be uploaded during publish” logic. - Added PHPUnit coverage for featured-image and inline-image self-heal behavior, including the “retry only once” ceiling.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
includes/class-publisher.php |
Adds bounded self-heal retry on blob-missing errors and refactors publish execution into attempt_publish_post(). |
includes/transformer/class-post.php |
Adds helpers to forget cached blob refs and enumerate attachment IDs whose blobs may be uploaded. |
tests/phpunit/tests/class-test-publisher.php |
Adds tests for stale blob ref recovery (featured + inline images) and single-retry limit. |
.github/changelog/fix-stale-featured-image-blob |
Adds a patch-level changelog entry describing the fix. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
WP_Error::get_error_data() can return a non-array; array-offset access on a string fatals on PHP 8 before the ?? defaults. Check is_array() first.
Blob-backed document content formats (Leaflet, pckt) upload a blob per core/image block, so the self-heal must clear every in-body image's cached ref, not just the four the Bluesky images embed uses. Otherwise a stale ref on the fifth-or-later image survives and the retry fails again.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Proposed changes:
Backfilling posts that have a featured image (or in-body images) to a self-hosted PDS fails with
atmosphere_pds: Could not find blob: bafkrei… (status 400). A blob's CID is cached in_atmosphere_blob_refpostmeta and reused on later publishes without re-uploading — but a blob is only retrievable from the PDS it was uploaded to, and only while a committed record references it. So when the active account/PDS changes (the reported case: published to Bluesky's PDS first, then switched to a self-hosted instance and backfilled), or the reference PDS garbage-collects an orphaned blob, the cached CID points at a blob the current PDS has never seen andapplyWritesrejects the whole batch.This PR automates the manual
delete_post_meta($id, '_atmosphere_blob_ref')workaround:publish_post()now detects a "Could not find blob" 400 fromapplyWrites, drops the cached refs for every image the post embeds (featured image and in-bodycore/imageattachments), and retries the publish once so the image is re-uploaded against the current PDS.attempt_publish_post()so the retry runs with fresh transformers (re-doing the blob upload the first attempt short-circuited from cache).reconcile_post_after_write()andatmosphere_publish_post_resultstill fire exactly once per call.Post::forget_image_blob()/Post::forget_post_image_blobs()/Post::embedded_image_attachment_ids()helpers keep the "which attachments does a publish upload" knowledge inside the transformer.debug_log()breadcrumb.Reported on the WordPress.org support forums: https://wordpress.org/support/topic/backfilled-posts-with-featured-images-fail-400-could-not-find-blob/ — the reporter confirmed they originally published to Bluesky's PDS and then switched to their own instance before backfilling.
Other information:
Testing instructions:
Automated:
npm run env-test -- --filter='test_publish_post_self_heals_stale_blob_ref|test_publish_post_self_heals_stale_inline_image_blob|test_publish_post_blob_self_heal_retries_only_once'— covers featured-image self-heal, in-body-image self-heal, and the single-retry ceiling.composer lint && npm run env-test(686 tests pass).Manual (reproduces the report):
_atmosphere_blob_refis cached on the attachment.ghcr.io/bluesky-social/pds).Could not find blob … (status 400). After: the image is re-uploaded to the new PDS and the post publishes (with adebug_logline noting the recovery whenWP_DEBUGis on).Changelog entry
A changelog entry is included at
.github/changelog/fix-stale-featured-image-blob(Patch / Fixed).