Skip to content

Try every metadata URI of an NFT instead of only the first - #3062

Open
jlobue10 wants to merge 1 commit into
Chia-Network:release/2.7.4from
jlobue10:feat/nft-metadata-uri-fallback
Open

Try every metadata URI of an NFT instead of only the first#3062
jlobue10 wants to merge 1 commit into
Chia-Network:release/2.7.4from
jlobue10:feat/nft-metadata-uri-fallback

Conversation

@jlobue10

@jlobue10 jlobue10 commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #3058, independent of #3060 / #3061 (targets release/2.7.4 like them; touches useMetadataData.ts in a different hunk than #3061, so either order merges cleanly).

Problem

The gallery's metadata loader fetched metadataUris[0] and gave up if that host failed, although NFTs commonly record several copies of their metadata (an HTTPS gateway URL plus an ipfs:// URI) and the data-file verifier already falls through its URI list. On a wallet with 445 NFTs whose first metadata URI is on nftstorage.link, every startup metadata pass is currently answered with the ipfs.io Cloudflare challenge, so those NFTs lose their names, traits, collection and preview URIs, while the ipfs:// copies of the same metadata were reachable all along. The Electron dapp-dialog path (parseCommandDisplay) already iterates metadata URIs; the renderer did not.

Change

  • fetchMetadataFromUris(uris, hash, fetchOne) (shared util) fetches the metadata from the first URI that serves it, in the order the minter recorded them. When every URI fails, a checksum mismatch outranks a download failure so a file that does not match the on-chain hash is never reported as merely unavailable; otherwise the first failure is reported. A mismatch on one URI does not stop the walk, in case another copy matches.
  • useMetadataData uses it instead of the first URI. useFetchAndProcessMetadata keeps its single-URI contract and shares the mismatch error constant.
  • NFTProvider.invalidateNFT invalidates every metadata URI, since any of them may have served the cached copy.

Combined with #3061 (configurable gateway), this restores metadata for NFTs whose primary host is challenging or gone but whose ipfs:// copy is pinned.

Verification

  • New unit tests for the helper: first URI wins without touching the rest, fall-through on host failure, first failure reported, mismatch outranks download failure, walk continues after a mismatch, empty/undefined URI list rejected before fetching.
  • packages/gui jest: 376/376. eslint and prettier clean; tsc unchanged for the touched files (the one pre-existing error in NFTProvider.tsx remains; the refactored promises array is now typed explicitly so it does not add implicit-any errors).
  • Built into a local checkout; will report the live-GUI check on this thread.

🤖 Generated with Claude Code


Note

Low Risk
Scoped to NFT gallery metadata fetch and cache invalidation in the GUI; no auth, payments, or chain logic, with behavior covered by new unit tests.

Overview
NFT metadata loading now walks the full metadataUris list (HTTPS gateway, ipfs://, etc.) instead of failing when only the first host is down, rate-limited, or blocked—matching how data files already use URI fallbacks.

A new fetchMetadataFromUris helper tries URIs in minter order, stops on first success, and defines failure precedence when all fail: checksum mismatch beats generic download errors, but a mismatch on one URI does not stop trying others. useMetadataData calls this helper; useFetchAndProcessMetadata shares the mismatch error string for that logic.

invalidateNFT now invalidates every metadata URI (not just the first), since any of them may have served cached metadata. Unit tests cover success, fall-through, error ordering, and empty URI lists.

Reviewed by Cursor Bugbot for commit 70702b5. Bugbot is set up for automated code reviews on this repo. Configure here.

@jlobue10
jlobue10 requested a review from a team as a code owner September 3, 2026 15:30
The gallery's metadata loader fetched `metadataUris[0]` and gave up if that
host failed, although NFTs commonly record several copies of their metadata
(an HTTPS gateway URL and an ipfs:// URI, say) and the data-file verifier
already falls through its URI list. With nftstorage.link challenging every
request, 445 NFTs in one wallet lost their names, traits and preview URIs
while their ipfs:// metadata copies were reachable all along (Chia-Network#3058).

Fetch the metadata from the first URI that serves it, in the order the
minter recorded them. When every URI fails, a checksum mismatch outranks a
download failure so a file that does not match the on-chain hash is never
reported as merely unavailable; otherwise the first failure is reported.
Refreshing an NFT now invalidates every metadata URI, since any of them may
have served the cached copy. The dapp-dialog path already tried every URI.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ni9VuLznDQTZh2V8aBis76
@jlobue10
jlobue10 force-pushed the feat/nft-metadata-uri-fallback branch from d5efc32 to 70702b5 Compare September 3, 2026 15:46
@jlobue10
jlobue10 changed the base branch from main to release/2.7.4 September 3, 2026 15:46
@jlobue10

jlobue10 commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

Live check on Linux (checkout built from this branch plus #3060/#3061, wallet with 445 NFTs whose first metadata URI is on nftstorage.link): on startup the metadata pass now falls through to the second URI for every one of them — 68 ipfs://…/metadata.json requests went out through the configured gateway within the first minutes, where before this change no ipfs:// metadata URI had ever been requested (0 such sidecars in a cache of 12k files). The fallback itself works as intended.

For the record, those particular files did not come back: the nft.storage-era CIDs turn out to be unpinned everywhere (ipfs.io itself returns 504 after a ~28 s DHT search, and mintgarden/filebase/pinata cannot find them either), so the second URI fails too and the NFT stays without metadata. That is a content problem, not a GUI one — the NFT in #3058 (BatGAN) is still pinned and does benefit.

@emlowe

emlowe commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

bugbot review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 70702b5. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants