Package: @walletconnect/logger@2.1.2
Summary
getLoggerContext (and everything built on it — generateChildLogger, formatChildLoggerContext) crashes at runtime in browsers when the underlying pino is v8 or newer:
TypeError: e.bindings is not a function
This currently fires for anyone who follows wagmi's own deprecation guidance on the walletConnect connector, which recommends overriding the vulnerable pino@7.11.0 to pino@10.0.0 (see the note in wagmi/connectors' walletConnect.d.ts). With that override in place, the very first EthereumProvider.init() throws as soon as the logger nests two child levels deep — i.e., WalletConnect is unusable in the browser on any secure pino.
Root cause
getLoggerContext duck-types the pino API like this (from logger/src/utils.ts, shown as shipped in dist/index.es.js):
function getLoggerContext(logger, customContextKey) {
let context = "";
return typeof logger.bindings === "undefined"
? (context = getBrowserLoggerContext(logger, customContextKey))
: (context = logger.bindings().context || ""),
context;
}
The assumption is: "if bindings exists, it's callable." That held for pino 7's browser build, where bindings was simply absent on browser loggers. From pino 8 onward, the browser build exposes bindings on child loggers as a plain data object, so the check passes and the call throws.
Empirical matrix (require('pino/browser.js'), then pino({}).child({}).bindings):
| pino |
root bindings |
child bindings |
| 7.11.0 |
undefined |
undefined ✅ |
| 8.21.0 |
undefined |
object 💥 |
| 9.14.0 |
undefined |
object 💥 |
| 10.0.0 |
undefined |
object 💥 |
The crash surfaces on the second nesting level: the first generateChildLogger(root, …) works (root has no bindings), attaches the custom context key, and returns a pino child — the next generateChildLogger(child, …) then hits the object-valued bindings and calls it.
Minimal reproduction
// npm i pino@10 @walletconnect/logger
const pino = require("pino/browser.js"); // what bundlers resolve for browser targets
const { generateChildLogger, getDefaultLoggerOptions } = require("@walletconnect/logger");
const root = pino(getDefaultLoggerOptions({ level: "error" }));
const core = generateChildLogger(root, "core"); // ok
const relayer = generateChildLogger(core, "relayer"); // TypeError: core.bindings is not a function
Suggested fix (one line)
Tighten the duck-type so any non-callable bindings falls back to the browser-context mechanism the module already has:
- return typeof logger.bindings === "undefined"
+ return typeof logger.bindings !== "function"
? (context = getBrowserLoggerContext(logger, customContextKey))
: (context = logger.bindings().context || ""), context;
This is behavior-identical on pino 7 (absent → fallback) and on Node builds (callable → used), and restores browser operation on pino ≥ 8. We've been running exactly this as a pnpm patch in production and can confirm the WalletConnect connector initializes and pairs normally with pino@10 under it. Happy to open a PR if useful.
Impact / context
- Anyone applying the remediation that wagmi's connector deprecation note prescribes (
"@walletconnect/logger": { "pino": "10.0.0" } override) ships this crash to every WalletConnect user of their dapp.
- Without the override, consumers are stuck on the vulnerable
pino@7.11.0 — so today the choice is "vulnerable dependency" or "broken connector". Fixing the duck-type (or bumping the pino dependency here with the API updates) resolves the dilemma at the source.
Package:
@walletconnect/logger@2.1.2Summary
getLoggerContext(and everything built on it —generateChildLogger,formatChildLoggerContext) crashes at runtime in browsers when the underlyingpinois v8 or newer:This currently fires for anyone who follows wagmi's own deprecation guidance on the
walletConnectconnector, which recommends overriding the vulnerablepino@7.11.0topino@10.0.0(see the note inwagmi/connectors'walletConnect.d.ts). With that override in place, the very firstEthereumProvider.init()throws as soon as the logger nests two child levels deep — i.e., WalletConnect is unusable in the browser on any secure pino.Root cause
getLoggerContextduck-types the pino API like this (fromlogger/src/utils.ts, shown as shipped indist/index.es.js):The assumption is: "if
bindingsexists, it's callable." That held for pino 7's browser build, wherebindingswas simply absent on browser loggers. From pino 8 onward, the browser build exposesbindingson child loggers as a plain data object, so the check passes and the call throws.Empirical matrix (
require('pino/browser.js'), thenpino({}).child({}).bindings):bindingsbindingsundefinedundefined✅undefinedundefinedundefinedThe crash surfaces on the second nesting level: the first
generateChildLogger(root, …)works (root has nobindings), attaches the custom context key, and returns a pino child — the nextgenerateChildLogger(child, …)then hits the object-valuedbindingsand calls it.Minimal reproduction
Suggested fix (one line)
Tighten the duck-type so any non-callable
bindingsfalls back to the browser-context mechanism the module already has:This is behavior-identical on pino 7 (absent → fallback) and on Node builds (callable → used), and restores browser operation on pino ≥ 8. We've been running exactly this as a
pnpm patchin production and can confirm the WalletConnect connector initializes and pairs normally withpino@10under it. Happy to open a PR if useful.Impact / context
"@walletconnect/logger": { "pino": "10.0.0" }override) ships this crash to every WalletConnect user of their dapp.pino@7.11.0— so today the choice is "vulnerable dependency" or "broken connector". Fixing the duck-type (or bumping the pino dependency here with the API updates) resolves the dilemma at the source.