Skip to content

fix(receive): avoid 'Mint info not initialized' when source mint is offline#1029

Closed
gudnuf wants to merge 2 commits into
masterfrom
fix/mint-info-not-initialized-on-offline-source
Closed

fix(receive): avoid 'Mint info not initialized' when source mint is offline#1029
gudnuf wants to merge 2 commits into
masterfrom
fix/mint-info-not-initialized-on-offline-source

Conversation

@gudnuf
Copy link
Copy Markdown
Contributor

@gudnuf gudnuf commented Apr 25, 2026

Summary

Pasting a Cashu token whose source mint is unreachable currently crashes the /receive/cashu/token flow with Mint info not initialized; call loadMint or loadMintFromCache first.

buildAccountForMint reads wallet.purpose before the existing !isOnline early-return. When the mint is unreachable, getInitializedCashuWallet returns the wallet without calling loadMintFromCache, so the purpose getter throws via getMintInfo(). Default purpose to 'transactional' when offline so the function reaches its offline placeholder branch as intended.

Recurring in production — Sentry issues AGICASH-9S, 9Y, 93, 7G, 7F, all on /receive/cashu/token.

Test plan

  • Generate a Cashu token from a mint, take the mint offline (or use a URL that resolves but doesn't respond), and paste the token at /receive/cashu/token. Should show the offline placeholder ("can't receive") rather than crashing the page.
  • Online happy path still works: pasting a token from a reachable mint resolves normally with the correct purpose.

@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 25, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agicash Ready Ready Preview, Comment Apr 28, 2026 5:09pm

Request Review

@supabase
Copy link
Copy Markdown

supabase Bot commented Apr 25, 2026

This pull request has been ignored for the connected project hrebgkfhjpkbxpztqqke because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

});

// wallet.purpose throws when offline (mint info wasn't loaded).
const purpose = isOnline ? wallet.purpose : 'transactional';
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

is it safe to default to transactional? can this cause some issues?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

hmm maybe not. My thinking at first was that it doesn't matter because the account is offline.

I asked claude and it pointed out that we would also need to handle the wallet being offline when checking canSendToLightning and canReceiveFromLightning because those use the mint info to check if nuts 4 or 5 are supported.

I think it might be better to check when receiving a token if the mint is offline and then throw and handle that error rather than trying to set a fake purpose and chasing down everywhere that relies on the wallet being online, wdyt?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think what would be safest is to introduce purpose unknown or something like that which will force us to handle it explicitly

gudnuf added 2 commits April 28, 2026 10:08
Pasting a Cashu token whose source mint is unreachable was crashing the
/receive/cashu/token flow with "Mint info not initialized; call loadMint
or loadMintFromCache first" (Sentry: AGICASH-9S, 9Y, 93, 7G, 7F).

buildAccountForMint read wallet.purpose before the !isOnline early
return. The purpose getter calls getMintInfo() internally, which throws
when mint info wasn't loaded. Add an 'unknown' AccountPurpose value
(in-memory only — DB enum unchanged) and use it as the local purpose
when offline. canSendToLightning then short-circuits correctly via its
existing `purpose !== 'transactional'` guard, so no further changes
to the lightning capability checks are needed.
decodeCashuToken unconditionally fetched the mint's keyset list to
resolve v2 truncated keyset IDs, then handed them to getDecodedToken.
For tokens with v1 keysets (full IDs embedded in the token) the network
call is unnecessary, and when the mint is offline it caused decode to
fail and the route loader to redirect away from /receive/cashu/token
before the receive page could render.

Try the bare decode first — succeeds for v1 keysets without any
network. Only fall back to fetching keysets when the bare decode
throws (the v2 truncated-ID case). Combined with the 'unknown'
purpose fix in the previous commit, pasting a v1-keyset token from
an offline mint now reaches the receive page, where
useCashuTokenWithClaimableProofs already surfaces "The mint that
issued this ecash is offline" via TokenErrorDisplay.
@gudnuf
Copy link
Copy Markdown
Contributor Author

gudnuf commented Apr 28, 2026

@jbojcic1 when I was testing this I realized there are more place we need to handle the source account being offline. This PR handles offline mints where the token has V1 keysets, but it throws on V2 keysets because our current code tries to decode them which requires the keys to be laoded.

I think this PR is more complex than its worth, so I opened an alternative in #1036

@jbojcic1
Copy link
Copy Markdown
Collaborator

@jbojcic1 when I was testing this I realized there are more place we need to handle the source account being offline. This PR handles offline mints where the token has V1 keysets, but it throws on V2 keysets because our current code tries to decode them which requires the keys to be laoded.

I think this PR is more complex than its worth, so I opened an alternative in #1036

what is the purpose of #1029 then? Should I review that one too?

@gudnuf
Copy link
Copy Markdown
Contributor Author

gudnuf commented Apr 30, 2026

@jbojcic1 when I was testing this I realized there are more place we need to handle the source account being offline. This PR handles offline mints where the token has V1 keysets, but it throws on V2 keysets because our current code tries to decode them which requires the keys to be laoded.
I think this PR is more complex than its worth, so I opened an alternative in #1036

what is the purpose of #1029 then? Should I review that one too?

Oh sorry, I meant #1037 is the alternative to this one #1029. If you agree that checking if the mint is online in the loader before loading the receve-cashu-token components, then we can close this one

export type AccountState = 'active' | 'expired';

export const AccountPurposeSchema = z.enum([
export const StoredAccountPurposeSchema = z.enum([
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I am not sure this is needed. We could just keep the same schema

}

if (receiveAccount.isUnknown && receiveAccount.type === 'cashu') {
if (!receiveAccount.isOnline || receiveAccount.purpose === 'unknown') {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

is it even possible that account has isOnline true and purpose unknown?

@gudnuf
Copy link
Copy Markdown
Contributor Author

gudnuf commented May 12, 2026

closing in favor of #1037 which checks if the mint can be reached in the loader so we don't have to change the receive flow

@gudnuf gudnuf closed this May 12, 2026
@gudnuf gudnuf deleted the fix/mint-info-not-initialized-on-offline-source branch May 12, 2026 21:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants