Skip to content

fix: handle rejected analytics request in WalletProvider.trackInitialization - #1408

Open
shlee-lab wants to merge 1 commit into
coinbase:mainfrom
shlee-lab:fix/analytics-unhandled-rejection
Open

fix: handle rejected analytics request in WalletProvider.trackInitialization#1408
shlee-lab wants to merge 1 commit into
coinbase:mainfrom
shlee-lab:fix/analytics-unhandled-rejection

Conversation

@shlee-lab

Copy link
Copy Markdown

Description

WalletProvider.trackInitialization() wraps sendAnalyticsEvent() in a try/catch, but the call isn't awaited. sendAnalyticsEvent is async and throws on a non-ok response:

if (!response.ok) {
  throw new Error(`HTTP error! status: ${response.status}`);
}

A synchronous try/catch can't see that rejection, so it escapes to the top level. Node has terminated the process on unhandled rejections by default since v15, so a failed analytics request takes the host application down about a second after the wallet provider is constructed.

It only shows up when the analytics request actually fails, which is probably why it hasn't come up on the usual CDP/Base setups. I ran into it on a custom EVM chain, where cca-lite.coinbase.com returns 400 for the unrecognised network_id. Anyone running offline or behind a firewall that blocks the endpoint should hit the same thing, since fetch rejects there too.

Observed on 0.10.4 in an MCP server built on AgentKit. The server finishes startup and answers initialize, then exits with:

Error: HTTP error! status: 400
    at sendAnalyticsEvent (.../analytics/sendAnalyticsEvent.js:50:15)
    at process.processTicksAndRejections (node:internal/process/task_queues:104:5)

Running the same binary with NODE_OPTIONS=--unhandled-rejections=warn keeps it alive, which confirms the rejection is what kills it.

The fix attaches .catch() so the existing warn-and-continue path actually runs. I kept the synchronous try/catch because getName(), getAddress() and getNetwork() are still called synchronously and can throw.

The Python implementation isn't affected. send_analytics_event is synchronous there, so its try/except already works.

Tests

Added should handle tracking rejections gracefully to walletProvider.test.ts. It mocks sendAnalyticsEvent to reject, then checks that the warning is logged and that no unhandledRejection fires.

Reverting the source change makes the new test fail, so it covers the actual regression:

✕ should handle tracking rejections gracefully   (without the fix)
✓ should handle tracking rejections gracefully   (with the fix)

The file's suite passes 5/5. eslint, tsc --noEmit and prettier --check are clean on the touched files.

@shlee-lab
shlee-lab requested a review from murrlincoln as a code owner August 7, 2026 12:30
@cb-heimdall

Copy link
Copy Markdown

🟡 Heimdall Review Status

Requirement Status More Info
Reviews 🟡 0/1
Denominator calculation
Show calculation
1 if user is bot 0
1 if user is external 0
2 if repo is sensitive 0
From .codeflow.yml 1
Additional review requirements
Show calculation
Max 0
0
From CODEOWNERS 0
Global minimum 0
Max 1
1
1 if commit is unverified 1
Sum 2

@github-actions github-actions Bot added documentation Improvements or additions to documentation wallet provider New wallet provider typescript labels Aug 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation typescript wallet provider New wallet provider

Development

Successfully merging this pull request may close these issues.

2 participants