Skip to content

Troubleshooting

View as Markdown

Use this page when the wallet integration exists but the dApp flow is failing or stalling.

The wallet fails before any UI appears, or initialization throws an origin error.

The embedded provider only accepts trusted iframe origins:

  • https://wallet.thru.org
  • http://localhost during development
  • the iframeUrl is an absolute URL
  • the origin is wallet.thru.org in production
  • you did not point the SDK at an arbitrary site or an app page that is not the wallet iframe

The dApp waits forever or users say the wallet never finishes connecting.

  • keep a visible “waiting for wallet approval” state while connect() is in flight
  • make sure the iframe is actually being shown
  • if you supplied metadata, make sure appId and appUrl match the dApp origin you expect
  • if the wallet is locked, expect passkey unlock before approval completes

The wallet rejects the request before the approval modal is useful.

  • the wallet is already connected before you call signTransaction()
  • the intent includes a valid programAddress
  • instructionData is a non-empty base64 string containing program instruction bytes
  • readWriteAddresses and readOnlyAddresses contain account addresses, not raw bytes
  • if you pass walletAddress, it matches the wallet account the user is acting as

The wallet iframe opens, but the request seems stuck.

  • do not hide the dApp loading state as soon as the wallet iframe appears
  • if the wallet is locked, the request may be waiting for passkey authentication
  • a request can also stall from the user perspective if the dApp immediately tears down the component that started the flow

signTransaction() succeeds, but there is no explorer entry.

The dApp never submitted the signed payload, or it submitted it against a different network than the explorer view you checked.

  • the dApp called thru.transactions.send(...) or an equivalent submit path after signing
  • the signed payload, not the unsigned payload, is what got submitted
  • the explorer network matches the RPC endpoint your dApp is using
  • if needed, inspect the result with Explorer MCP

The transaction signs cleanly, but the app expected a different network fee payer or signer.

  • do not assume the selected managed account is also the network signer
  • use getSigningContext() for display or diagnostics when the UI needs to show the current signer split
  • do not prebuild the final transaction wire payload for the browser wallet flow
  • let signTransaction(intent) choose the fee payer, order accounts, fill headers and nonces, and return the final signed bytes

The app signs successfully but then fails after trying to reshuffle signature bytes and transaction payload bytes before submission.

  • signTransaction() now returns canonical raw transaction bytes ready for direct submission
  • do not prepend, append, or reorder signature bytes yourself after the wallet returns the result
  • send the returned bytes directly through thru.transactions.send(...)

The wallet says the transaction is invalid or signing fails unexpectedly.

  • the program instruction bytes came from a correct instruction builder
  • the instruction bytes are base64 encoded before they are assigned to instructionData
  • the account selection and fee payer assumptions match the wallet-managed signing model
  • the app is not treating the selected managed account as the network signer without checking getSigningContext()

session.signTransaction(...) fails with a missing or unknown session error.

  • the session was created or confirmed in the same app storage scope
  • getSigningSessions() returns the session before you try to use it
  • the session has not expired
  • the user has not revoked it in the wallet
  • if you used createSigningSessionInstruction(...), the transaction that added the session authority landed before you called confirmSigningSession(id)