Skip to content

fix(wallets): log WalletNotAvailableError at warn instead of error#1846

Open
devin-ai-integration[bot] wants to merge 3 commits into
mainfrom
devin/1779181695-fix-wallet-not-found-log-level
Open

fix(wallets): log WalletNotAvailableError at warn instead of error#1846
devin-ai-integration[bot] wants to merge 3 commits into
mainfrom
devin/1779181695-fix-wallet-not-found-log-level

Conversation

@devin-ai-integration
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot commented May 19, 2026

Description

The WithLoggerContext decorator unconditionally logged all thrown errors at error level. For WalletNotAvailableError — a normal business outcome indicating "wallet not found" — this generated thousands of error-level entries in Datadog (17K+ logs over the past week from lobster.cash alone).

WalletNotAvailableError is expected in locator-iteration and existence-check flows (e.g., when looking up wallets across chains). The error is caught and handled by consumers, but the SDK's decorator had already logged it at error level.

Changes:

  1. packages/common/base/src/logger/decorators.ts — Add an expectedErrors option to WithLoggerContextOptions. Errors matching any of the listed classes are logged at warn instead of error. Backwards-compatible: when expectedErrors is not provided, behavior is unchanged.

  2. packages/wallets/src/wallets/wallet-factory.ts — Mark WalletNotAvailableError as an expected error in the walletFactory.getWallet decorator.

  3. packages/common/base/src/logger/decorators.test.ts — Unit tests covering the new expectedErrors branch (expected → warn, unexpected → error, omitted → error, sync methods, error rethrow).

Test plan

  • New unit tests for WithLoggerContext decorator's expectedErrors behavior (5 tests):
    • Expected errors logged at warn level
    • Unexpected errors logged at error level
    • All errors logged at error when expectedErrors omitted (backwards-compat)
    • Errors still rethrown in all cases
    • Sync method support
  • All existing wallets-sdk tests pass (319 tests, 0 failures)
  • All common-sdk-base tests pass (15 tests, 0 failures)
  • Lint checks pass
  • Smoke test failure is unrelated (UI transfer button interaction)

Package updates

  • @crossmint/common-sdk-base: patch — add expectedErrors option to WithLoggerContext
  • @crossmint/wallets-sdk: patch — use expectedErrors for WalletNotAvailableError in getWallet

Changeset added via .changeset/fix-wallet-not-found-log-level.md.

Link to Devin session: https://crossmint.devinenterprise.com/sessions/638aa84609aa47e0b2894361307de295
Requested by: @aigustin

devin-ai-integration Bot and others added 2 commits May 19, 2026 09:08
The WithLoggerContext decorator unconditionally logged all thrown errors
at error level. For WalletNotAvailableError this is a normal business
outcome (wallet not found) used in locator-iteration and existence-check
flows, yet it generated thousands of error-level entries in Datadog.

Add an expectedErrors option to WithLoggerContext so decorated methods
can declare which error classes represent expected outcomes. Matching
errors are now logged at warn level instead of error.

Mark WalletNotAvailableError as expected in walletFactory.getWallet.

Co-Authored-By: Agus <agustin@paella.dev>
Co-Authored-By: Agus <agustin@paella.dev>
@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

Original prompt from Agus

SYSTEM:
=== BEGIN THREAD HISTORY (in #team-agents-development) ===
Guille (U09TCQZ6L2C): just flagging that we are getting a ton of errors on DD because the wallets sdk is not finding a wallet for a specific user.

@Agus (U078SGS1ZFV) do you know if this is the expected behavior? I presume this should be a warn rather than an error.

just asking before escalating or proposing a fix on any side

ATTACHMENT:"https://crossmint.devinenterprise.com/attachments/13e89e51-c1cb-4fac-8e09-81297b3bf401/CleanShot+2026-05-18+at+12.48.16.png"

Alfonso Gomez Jordana Manas (U0365GYG4KH): i would ask wallets

<most_recent_message>
Agus (U078SGS1ZFV): Hmm @Guille (U09TCQZ6L2C) it might be that when we created the user we failed to create the solana wallet and just created the base one? In this case we should just create the wallet since the user should have both

@Devin can you investigate?
</most_recent_message>
=== END THREAD HISTORY ===

Thread URL: https://crossmint.slack.com/archives/C0AJ23LAPEW/p1779101456293709?thread_ts=1779101456.293709&amp;cid=C0AJ23LAPEW

The latest message is the one right above that tagged you. The <most_recent_message> is the message that you should use to guide your goals + task for this session, and you should use the rest of the slack thread as context.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 19, 2026

🦋 Changeset detected

Latest commit: 224b979

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 18 packages
Name Type
@crossmint/common-sdk-base Patch
@crossmint/wallets-sdk Patch
@crossmint/client-sdk-auth Patch
@crossmint/client-sdk-base Patch
@crossmint/client-sdk-react-base Patch
@crossmint/client-sdk-react-native-ui Patch
@crossmint/client-sdk-react-ui Patch
@crossmint/client-sdk-verifiable-credentials Patch
@crossmint/client-sdk-smart-wallet Patch
@crossmint/client-sdk-walletconnect Patch
@crossmint/common-sdk-auth Patch
@crossmint/server-sdk Patch
@crossmint/wallets-quickstart-devkit Patch
@crossmint/wallets-playground-react Patch
@crossmint/client-sdk-nextjs-starter Patch
@crossmint/wallets-playground-expo Patch
@crossmint/auth-ssr-nextjs-demo Patch
crossmint-auth-node Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 19, 2026

Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
packages/wallets/src/wallets/wallet-factory.ts:92-98
**Double warn-level log for `WalletNotAvailableError`**

The method already logs `walletFactory.getWallet.notFound` at `warn` on line 94 before throwing. With `WalletNotAvailableError` now in `expectedErrors`, the decorator will also emit a second `warn` log (`walletFactory.getWallet threw an error`). Every wallet-not-found case produces two warn entries — previously it was one `warn` + one `error`. This was a pre-existing pattern, but worth confirming the team is comfortable having duplicate warn logs in place of the prior error-level noise.

### Issue 2 of 2
packages/common/base/src/logger/decorators.ts:109-120
**No unit tests for the new `expectedErrors` branch**

The `logThrownError` helper introduces a new code path (warn vs. error selection) that has no test coverage — there are currently no test files under `packages/common/base/src/logger/`. A test verifying that an expected-error class triggers `logger.warn` while an unexpected error triggers `logger.error` (and that the error is still re-thrown in both cases) would prevent silent regressions to this decorator, which is shared across the SDK.

Reviews (1): Last reviewed commit: "chore: add changeset for expected-errors..." | Re-trigger Greptile

Comment on lines +109 to +120
function logThrownError(
options: Pick<WithLoggerContextOptions, "logger" | "methodName" | "expectedErrors">,
error: unknown
): void {
const isExpected = options.expectedErrors?.some((ErrorClass) => error instanceof ErrorClass) ?? false;
const message = `${options.methodName} threw an error`;
if (isExpected) {
options.logger.warn(message, { error });
} else {
options.logger.error(message, { error });
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 No unit tests for the new expectedErrors branch

The logThrownError helper introduces a new code path (warn vs. error selection) that has no test coverage — there are currently no test files under packages/common/base/src/logger/. A test verifying that an expected-error class triggers logger.warn while an unexpected error triggers logger.error (and that the error is still re-thrown in both cases) would prevent silent regressions to this decorator, which is shared across the SDK.

Rule Used: Add unit tests when implementing new validation lo... (source)

Learned From
Paella-Labs/crossbit-main#21014

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/common/base/src/logger/decorators.ts
Line: 109-120

Comment:
**No unit tests for the new `expectedErrors` branch**

The `logThrownError` helper introduces a new code path (warn vs. error selection) that has no test coverage — there are currently no test files under `packages/common/base/src/logger/`. A test verifying that an expected-error class triggers `logger.warn` while an unexpected error triggers `logger.error` (and that the error is still re-thrown in both cases) would prevent silent regressions to this decorator, which is shared across the SDK.

**Rule Used:** Add unit tests when implementing new validation lo... ([source](https://app.greptile.com/review/custom-context?memory=9dc35ad5-5868-49a3-bbcb-a42edc5ee697))

**Learned From**
[Paella-Labs/crossbit-main#21014](https://github.com/Paella-Labs/crossbit-main/pull/21014)

How can I resolve this? If you propose a fix, please make it concise.

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.

Fair point, you sneaky little gecko 🐍 — adding tests now for the expectedErrors branch. Will push shortly.

@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

Good catch, cold-blooded code reviewer 🦎 — you're right that there are now two warn-level logs for the not-found case.

However, they serve complementary purposes:

  • Method-level warn (walletFactory.getWallet.notFound): includes the raw API error response — useful for debugging specific lookup failures
  • Decorator-level warn (walletFactory.getWallet threw an error): includes the full error object with execution context — useful for tracing across the SDK

The primary goal here is eliminating the error-level noise in Datadog (17K+ false error entries/week). Two warn-level entries are a significant improvement over one warn + one error, and the deduplication can be a follow-up if the team finds the warn volume too chatty.

…decorator

Co-Authored-By: Agus <agustin@paella.dev>
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 19, 2026

Reviews (2): Last reviewed commit: "test(logger): add unit tests for expecte..." | Re-trigger Greptile

@github-actions
Copy link
Copy Markdown
Contributor

🔥 Smoke Test Results

Status: Failed

Statistics

  • Total Tests: 5
  • Passed: 3 ✅
  • Failed: 1 ❌
  • Skipped: 1 ⚠️
  • Duration: 4.95 min

Test Details


This is a non-blocking smoke test. Full regression tests run separately.

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.

1 participant