---
summary: Fix pino-redact crash on Node 25 when AbortSignal in log payload — sanitizeLogBindings, 14 new tests
breaking: false
---

# 0.3.7 — 2026-04-19

Fixes a crash introduced on Node 25+ when passing the handler `Context` object as log bindings to `fetchWithTimeout` / `withRetry` (or any logger call).

## Fixed

- **Logger: pino-redact crash on Node 25 when context includes `AbortSignal`** (#32) — `@pinojs/redact`'s wildcard traversal (`*.*.field`) invokes `AbortSignal.aborted` with a non-branded receiver, which Node 25 now rejects with `TypeError: The AbortSignal.aborted getter can only be used on instances of AbortSignal`. Every tool/resource call whose log payload contained `ctx.signal` (or any non-plain-prototype object) crashed before fetch completion. Fix: a new `sanitizeLogBindings` step wired into pino's `formatters.log` strips functions and non-plain-prototype instances (`AbortSignal`, `Map`, `Set`, storage handles, etc.), converts `Date`/`URL` to strings, preserves primitives/plain objects/arrays/`Error` instances, and caps recursion depth at 4. Runs before redact traversal, so sensitive-field redaction continues to work unchanged.
- **Logger: `err` field no longer pre-serialized before pino sees it** — the manual `pino.stdSerializers.err(error)` call in `Logger.log` produced an object with `pinoErrProto` that the sanitizer would reject. The raw `Error` is now passed through, letting pino's default `err` serializer run *after* `formatters.log`.

## Changed

- **`fetchWithTimeout` / `withRetry` JSDoc** — clarified that the `context` / `options.context` parameter represents log bindings, and noted that passing the handler `Context` directly is safe (the logger sanitizes non-serializable fields). The ergonomic example pattern is unchanged.

## Tests

- **9 new sanitizer unit tests** — primitive/plain-object passthrough; `AbortSignal` stripping with a `Proxy` trip-wire asserting `aborted` is never accessed; function/method-handle stripping; `Date`/`URL` conversion; recursive non-plain-object stripping; `Map`/`Set` drop; `Error` instance preservation; circular reference survival; depth-cap truncation.
- **`fast-check` fuzz (200 runs)** — mixed-shape bindings (primitives, plain objects, `AbortSignal`, `Map`, `Set`, `Promise`, `Date`, `URL`, `Error`, functions) asserting no throws and JSON-serializable output.
- **5 new logger integration tests** — end-to-end verification with real pino: framework `Context`-like object through `logger.info`; `fetchWithTimeout` with ctx-like bindings; `withRetry` with ctx-like bindings; sensitive-field redaction still applies after sanitization; `Error` with `.cause` chain serializes correctly through pino's `err` serializer after `formatters.log` runs.
