fix(images): swallow RuntimeBinderException in cover-lookup fallback#600
Draft
kevinheneveld wants to merge 1 commit into
Draft
fix(images): swallow RuntimeBinderException in cover-lookup fallback#600kevinheneveld wants to merge 1 commit into
kevinheneveld wants to merge 1 commit into
Conversation
kevinheneveld
pushed a commit
to kevinheneveld/Listenarr
that referenced
this pull request
May 18, 2026
…rafting
State on top of the post-rebase baseline:
- 5 more commits on kevin/live (preview button, hydrated audiobook,
publish-date normalize, image-500 fix, modal z-index prop)
- PR Listenarrs#600 + Listenarrs#603 opened (defensive fixes, non-draft)
- PR Listenarrs#604 + Listenarrs#605 opened as drafts (wave 1 of the staggered
feature-PR queue per Kevin's pacing instruction)
- Issue #5 filed for LibriVox metadata source (deferred)
- 8 features on kevin/live still without an upstream PR — queued
with a per-day schedule
Live image: listenarr:local-20260517-1651 (head a712b49).
Two-step rollback: 1634 → 1617.
kevinheneveld
pushed a commit
to kevinheneveld/Listenarr
that referenced
this pull request
May 18, 2026
- Live image bumped to listenarr:local-20260518-0750 (head 40a436b). - PR Listenarrs#580 rewritten on review feedback from T4g1: NzbgetSafeRedirectHandler replaces URL-embedded creds, covers both /xmlrpc and /jsonrpc. - All 9 open upstream PRs are now draft (converted Listenarrs#580, Listenarrs#600, Listenarrs#603). - kevin/live and kevin/live-rebased both carry the new commit. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
kevinheneveld
pushed a commit
to kevinheneveld/Listenarr
that referenced
this pull request
May 18, 2026
- Live image bumped to listenarr:local-20260518-0750 (head 40a436b). - PR Listenarrs#580 rewritten on review feedback from T4g1: NzbgetSafeRedirectHandler replaces URL-embedded creds, covers both /xmlrpc and /jsonrpc. - All 9 open upstream PRs are now draft (converted Listenarrs#580, Listenarrs#600, Listenarrs#603). - kevin/live and kevin/live-rebased both carry the new commit. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
ImagesController.GetImage's fallback metadata-driven cover path accesses fields via dynamic on the object? returned by GetMetadataAsync. When the returned envelope shape lacks the expected "metadata" property — which happens when one of the upstream sources (e.g., Audnexus) 500s and the service still returns a partial envelope — the C# dynamic binder throws RuntimeBinderException. That exception type wasn't in IsRecoverableImageLookupException's whitelist, so it bypassed the surrounding catch-when filter and bubbled to the outer handler. The whole image endpoint then returned 500 instead of falling through to the next candidate URL (OpenLibrary ISBN cover, etc.) or the placeholder. Add RuntimeBinderException to the recoverable list. The dynamic access stays — this just makes its failure mode match the existing "log debug and continue" pattern used for IOException / JsonException / HttpRequestException etc. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
c513aac to
c459668
Compare
kevinheneveld
pushed a commit
to kevinheneveld/Listenarr
that referenced
this pull request
May 19, 2026
…rafting
State on top of the post-rebase baseline:
- 5 more commits on kevin/live (preview button, hydrated audiobook,
publish-date normalize, image-500 fix, modal z-index prop)
- PR Listenarrs#600 + Listenarrs#603 opened (defensive fixes, non-draft)
- PR Listenarrs#604 + Listenarrs#605 opened as drafts (wave 1 of the staggered
feature-PR queue per Kevin's pacing instruction)
- Issue #5 filed for LibriVox metadata source (deferred)
- 8 features on kevin/live still without an upstream PR — queued
with a per-day schedule
Live image: listenarr:local-20260517-1651 (head a712b49).
Two-step rollback: 1634 → 1617.
kevinheneveld
pushed a commit
to kevinheneveld/Listenarr
that referenced
this pull request
May 19, 2026
- Live image bumped to listenarr:local-20260518-0750 (head 40a436b). - PR Listenarrs#580 rewritten on review feedback from T4g1: NzbgetSafeRedirectHandler replaces URL-embedded creds, covers both /xmlrpc and /jsonrpc. - All 9 open upstream PRs are now draft (converted Listenarrs#580, Listenarrs#600, Listenarrs#603). - kevin/live and kevin/live-rebased both carry the new commit. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
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.
Summary
ImagesController.GetImage's fallback metadata-driven cover path accesses fields viadynamicon theobject?returned byGetMetadataAsync. When the returned envelope shape lacks the expectedmetadataproperty — which happens when one of the upstream sources (e.g., Audnexus) 500s and the service still returns a partial envelope — the C# dynamic binder throwsRuntimeBinderException.That exception type isn't in
IsRecoverableImageLookupException's whitelist, so it bypasses the surroundingcatch whenfilter and bubbles to the outer handler. The whole image endpoint then returns 500 instead of falling through to the next candidate URL (OpenLibrary ISBN cover, etc.) or the placeholder.Repro
In live logs after a metadata-backfill modal search, six candidates returned 500 from
/api/v1/images/{asin}for ASINs B0DPMHF5HN, B009S8FKUU, B0H23C15LQ, B002VEU2PQ, B0DPMFLQPH, B0DPMCLFLD. Each is preceded by[WRN] [Listenarr.Application.Metadata.AudnexusService] Audnexus API returned status code InternalServerError for ASIN ...and[INF] Successfully fetched metadata from Audible for ASIN: ...— the Audible response succeeds, but the envelope shape doesn't have ametadatamember. Each then logs:Line 610 is
object? mdObj = env.metadata;— thedynamicaccess. UI-side: those candidates render with the browser's broken-image icon in the metadata-backfill modal candidate list.Fix
Add
Microsoft.CSharp.RuntimeBinder.RuntimeBinderExceptiontoIsRecoverableImageLookupException. The dynamic access stays — this just makes its failure mode match the existing "log debug and continue" pattern used forIOException/JsonException/HttpRequestExceptionetc. The lookup falls through to the next candidate URL or the placeholder, same as any other recoverable failure.A larger refactor that replaces the
dynamicaccess with a strongly-typed shape would be cleaner but is out of scope for this defensive patch.Test plan
/api/v1/images/{asin}, log shows[DBG] Failed to parse fallback metadata envelope for {Identifier}and the lookup falls through.🤖 Generated with Claude Code