{"record":{"id":"c7131e9dec08400f","repo":"unionlabs/union","slug":"no-wallet-available","errorCode":null,"errorMessage":"No wallet available","messagePattern":"No wallet available","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"app2/src/routes/btcfi/step/Step3.svelte","lineNumber":107,"sourceCode":"  }\n\n  if (!isEvmAddressValid) {\n    return\n  }\n\n  const addressToUse = evmAddress.trim()\n  isLoading = true\n\n  const message =\n    `I verify that I own this Babylon address and want to receive BTCfi rewards on Ethereum address: ${addressToUse}`\n\n  runPromise(\n    pipe(\n      Effect.sync(() => {\n        const walletApi = cosmosStore.connectedWallet\n          && (window as any)[cosmosStore.connectedWallet]\n        if (!walletApi) {\n          throw new Error(\"No wallet available\")\n        }\n        return walletApi\n      }),\n      Effect.flatMap((walletApi) =>\n        Effect.tryPromise({\n          try: () => {\n            const chainId = \"bbn-1\"\n            return walletApi.signArbitrary(chainId, walletAddress, message)\n          },\n          catch: (error) => new Error(`Failed to sign message: ${error}`),\n        })\n      ),\n      Effect.flatMap((signature) =>\n        verifyBTCFIWallet({\n          bbnAddress: walletAddress,\n          message,\n          signature: JSON.stringify(signature),\n          evmAddress: addressToUse,","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/unionlabs/union/blob/031785bb6dc6b957c624e62bc64c184409c97d7b/app2/src/routes/btcfi/step/Step3.svelte#L89-L125","documentation":"Thrown in the BTCfi Step3 flow (app2) when preparing to sign a Babylon ownership message: the app takes the stored wallet name from cosmosStore.connectedWallet and looks up the injected provider via window[connectedWallet]; if that global is absent, there is no wallet API to call signArbitrary on and the Effect fails synchronously.","triggerScenarios":"cosmosStore.connectedWallet is set (e.g. \"keplr\" or \"leap\") but the corresponding window global is missing: extension uninstalled/disabled, injection not finished at call time, the name restored from persisted state after a browser profile change, or a non-cosmos wallet was connected.","commonSituations":"User disabled the extension between sessions; page loaded and user clicked through before injection (race); localStorage/session persisted connectedWallet stale; mobile in-app browser without the extension.","solutions":["Reconnect the wallet (trigger the connect flow again) so connectedWallet matches a currently injected provider","Verify the extension is installed and enabled for the site, then reload","Clear stale connection state when window[connectedWallet] is missing instead of attempting to sign"],"exampleFix":"// before\nconst walletApi = cosmosStore.connectedWallet && (window as any)[cosmosStore.connectedWallet]\n\n// after (gate the flow and re-connect on miss)\nconst walletApi = cosmosStore.connectedWallet && (window as any)[cosmosStore.connectedWallet]\nif (!walletApi) {\n  cosmosStore.connectedWallet = null // clear stale state\n  await reconnect() // run the wallet-connect flow again\n  return\n}","handlingStrategy":"validation","validationCode":"const walletName = cosmosStore.connectedWallet\nconst walletApi = walletName && (window as any)[walletName]\nif (!walletApi || typeof walletApi.signArbitrary !== \"function\") {\n  cosmosStore.connectedWallet = null // clear stale state\n  // trigger the connect flow instead of signing\n}","typeGuard":"const isInjectedCosmosWallet = (w: unknown): w is { signArbitrary: (chainId: string, signer: string, message: string) => Promise<unknown> } =>\n  typeof w === \"object\" && w !== null && typeof (w as any).signArbitrary === \"function\"","tryCatchPattern":"try {\n  // Effect pipeline already routes this via Effect.orElse; for plain code:\n  await walletApi.signArbitrary(\"bbn-1\", address, message)\n} catch (error) {\n  if ((error as Error).message === \"No wallet available\") {\n    // prompt reconnect; do not retry until window global exists\n  }\n  throw error\n}","preventionTips":["Verify window[connectedWallet] exists before enabling the sign action","Clear persisted connection state on page load if the provider global is missing","Handle wallet injection races (window onload / extension events) before user actions"],"tags":["wallet","cosmos","ui","injection"],"backgroundTag":null,"analyzedSha":"031785bb6dc6b957c624e62bc64c184409c97d7b","analyzedAt":"2026-08-16T06:24:09.996Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}