Skip to content

fix(ai): render debug meta portably in ConsoleLogger so payloads survive Cloudflare Workers#734

Merged
tombeckenham merged 3 commits into
TanStack:mainfrom
season179:fix/console-logger-workerd-meta
Jun 10, 2026
Merged

fix(ai): render debug meta portably in ConsoleLogger so payloads survive Cloudflare Workers#734
tombeckenham merged 3 commits into
TanStack:mainfrom
season179:fix/console-logger-workerd-meta

Conversation

@season179

@season179 season179 commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Fixes #730

Problem

With the default logger (debug: true), the per-category headlines print but the meta payloads never reach the terminal when chat() runs on Cloudflare Workers / workerd (wrangler dev, Miniflare, TanStack Start on Workers). Debug mode is effectively headers-only: no request bodies, no chunk contents, no RUN_ERROR payloads.

The issue suggested the Node-only console.dir options were to blame, but the mechanism turned out to be broader: workerd never forwards console.dir output to the terminal at all — with options, without options, even for plain strings. Verified empirically against real workerd.

A second trap surfaced while fixing it: under the nodejs_compat flag (which TanStack Start on Cloudflare uses), workerd emulates process.versions.node (reports "22.14.0"), so the naive process.versions?.node runtime check routes Workers down the Node path — the exact runtime that's broken. Detection has to rule out workerd first via its navigator.userAgent === 'Cloudflare-Workers' marker.

Fix

ConsoleLogger now renders meta with a per-runtime strategy:

Runtime Strategy Why
Node console.dir(meta, { depth: null, colors: true }) (unchanged) depth-unlimited inspect; console.debug(msg, meta) truncates at depth 2
Cloudflare Workers circular-safe pretty-printed JSON appended to the message console.dir is dropped entirely, and workerd's own inspect of extra console args truncates nested objects
Browsers / Deno / Bun meta as a second console argument collapsible trees in devtools, native circular-ref handling

The JSON serializer handles circular references ("[Circular]"), Error instances (which JSON.stringify would render as {} — and RUN_ERROR payloads are the headline case), and bigint. Logging can never throw into the host app: if serialization and even String() coercion fail, it falls back to a placeholder.

Tests

  • Unit (packages/ai/tests/logger/console-logger.test.ts): all three strategies, including the nodejs_compat fake-Node trap, circular refs, Error/bigint serialization, the never-throws guarantee, and message-before-meta ordering on Node.
  • E2E (testing/e2e/tests/workerd-console-logger.spec.ts): runs the built logger inside real workerd via Miniflare with nodejs_compat enabled, captures runtime stdio, and asserts payloads arrive at full depth (a depth-5 marker proves the JSON path — workerd's inspect would truncate it), errors keep their message, and circular meta survives. miniflare is a devDependency of the e2e package only; workerd was already in the lockfile via wrangler.

Notes

  • Logger interface JSDoc in types.ts updated to describe the new default rendering.
  • Lockfile: besides the miniflare tree, pnpm deduped ws 8.19.0 → 8.20.1 (within all consumers' ranges) and dropped an orphaned undici@7.16.0 entry.
  • Known limitation: workerd builds without nodejs_compat that also lack the userAgent marker would fall through to the second-argument path — still visible output, just shallower than JSON.

Summary by CodeRabbit

  • Bug Fixes

    • Console logger now preserves structured metadata across runtimes and safely serializes circular objects, Errors, and bigints.
  • Tests

    • Added/expanded unit and end-to-end tests covering Node and Cloudflare Workers runtimes, ordering, teardown, circular references, errors, and deep nested meta.
  • Documentation

    • Updated logger docs to describe structured-meta forwarding and runtime rendering.
  • Chores

    • Added tooling dependency to enable workerd e2e testing.

…orkers (TanStack#730)

workerd never forwards console.dir output to the terminal, so the default
debug logger printed category headlines but dropped every meta payload on
Cloudflare Workers. ConsoleLogger now picks a per-runtime strategy: Node
keeps the depth-unlimited console.dir dump, Workers gets circular-safe
pretty-printed JSON appended to the message, and other runtimes receive
meta as a second console argument.

Detection checks workerd's navigator.userAgent marker before
process.versions.node, since nodejs_compat emulates a Node version string
and would otherwise route Workers down the broken Node path.

Adds a Miniflare-based e2e spec that runs the built logger inside real
workerd and asserts payloads reach the log stream at full depth.
@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c2acb6cd-669c-474e-a672-03e2efa181fd

📥 Commits

Reviewing files that changed from the base of the PR and between 0f1f2ce and a020e86.

📒 Files selected for processing (2)
  • packages/ai/src/logger/console-logger.ts
  • testing/e2e/tests/workerd-console-logger.spec.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • testing/e2e/tests/workerd-console-logger.spec.ts
  • packages/ai/src/logger/console-logger.ts

📝 Walkthrough

Walkthrough

This PR fixes debug logging on Cloudflare Workers/workerd by replacing Node-only console.dir options with a runtime-aware strategy: Node continues using console.dir, workerd receives circular-safe JSON appended to the message, and other runtimes receive meta as an extra console argument. The fix includes runtime detection, serialization helpers, comprehensive unit tests, and E2E validation via Miniflare.

Changes

ConsoleLogger workerd meta payload fix

Layer / File(s) Summary
Meta strategy detection and ConsoleLogger refactor
packages/ai/src/logger/console-logger.ts
Introduces MetaStrategy type, resolveMetaStrategy() detector that checks workerd navigator.userAgent before process.versions.node, DIR_OPTIONS, and stringifyMetaSafely() to serialize meta while handling circular references, Error objects, and bigint values. Refactors ConsoleLogger to centralize logging in a private emit() method that routes to appropriate meta rendering per runtime.
Logger interface documentation
packages/ai/src/logger/types.ts
Updates JSDoc for Logger interface meta parameter to document runtime-specific behavior: Node uses depth-unlimited console.dir, workerd appends circular-safe JSON to message, other runtimes receive meta as second console argument.
Unit test coverage for all runtime strategies
packages/ai/tests/logger/console-logger.test.ts
Adds global stub cleanup via vi.unstubAllGlobals() and comprehensive test coverage for Node console.dir ordering, workerd JSON serialization with deep objects/circular refs/Error/bigint, and non-Node fallback behavior. Validates logging never throws on hostile meta, falling back to "[Unserializable meta]" marker.
Changeset release metadata
.changeset/console-logger-workerd-meta.md
Documents patch for @tanstack/ai fixing meta payload loss on Cloudflare Workers through runtime-specific meta rendering and proper detection order.
E2E test with Miniflare workerd runtime
testing/e2e/package.json, testing/e2e/tests/workerd-console-logger.spec.ts
Adds miniflare dev dependency and Playwright test that builds a worker script with compiled ConsoleLogger, runs it in Miniflare with nodejs_compat enabled, exercises debug/error/warn with deep meta and circular payloads, captures stdout/stderr, and asserts nested data survives to depth 5 with proper error and circular serialization.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A logger once lost in the Workers' deep night,
We taught it to choose how to show meta just right.
Node keeps console.dir with colors aglow,
Workerd gets safe JSON, circulars in tow.
Now every runtime hears the full debug bite.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed Title clearly identifies the primary fix: making ConsoleLogger render debug meta payloads in a portable way that works on Cloudflare Workers/workerd, directly addressing issue #730.
Description check ✅ Passed Description covers problem, fix, testing strategy, and notes but does not explicitly check all template sections (problem section exists but does not map to template's 'Changes' heading; no explicit checklist completion shown).
Linked Issues check ✅ Passed All coding objectives from #730 are met: portable meta rendering per-runtime, circular-safe serializer, nodejs_compat detection via userAgent, Error/bigint handling, and never-throws guarantee, with comprehensive unit and E2E test coverage.
Out of Scope Changes check ✅ Passed All changes are in-scope: ConsoleLogger implementation, Logger interface JSDoc, comprehensive test coverage (unit and E2E), miniflare devDependency, and changeset documentation. No unrelated refactoring detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

testing/e2e/tests/workerd-console-logger.spec.ts

Parsing error: "parserOptions.project" has been provided for @typescript-eslint/parser.
The file was not found in any of the provided project(s): testing/e2e/tests/workerd-console-logger.spec.ts


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@socket-security

socket-security Bot commented Jun 10, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedminiflare@​4.20260609.09910010096100

View full report

@season179 season179 marked this pull request as ready for review June 10, 2026 00:32

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ee9af98c-fa86-427a-8143-f969e7ddc4a8

📥 Commits

Reviewing files that changed from the base of the PR and between e8ce0e1 and 3f6916a.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (6)
  • .changeset/console-logger-workerd-meta.md
  • packages/ai/src/logger/console-logger.ts
  • packages/ai/src/logger/types.ts
  • packages/ai/tests/logger/console-logger.test.ts
  • testing/e2e/package.json
  • testing/e2e/tests/workerd-console-logger.spec.ts

Comment thread testing/e2e/tests/workerd-console-logger.spec.ts
season179 and others added 2 commits June 10, 2026 08:44
… aimock

aimock mocks provider LLM responses; this spec exercises console rendering
inside the workerd runtime, a path provider HTTP never reaches. Wiring
aimock in would mean bundling the whole chat() + adapter stack into the
Miniflare worker without covering any additional fixed behavior.
@nx-cloud

nx-cloud Bot commented Jun 10, 2026

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit a020e86

Command Status Duration Result
nx run-many --targets=build --exclude=examples/... ✅ Succeeded 1m 13s View ↗

☁️ Nx Cloud last updated this comment at 2026-06-10 06:00:36 UTC

@tombeckenham tombeckenham self-requested a review June 10, 2026 05:58
@pkg-pr-new

pkg-pr-new Bot commented Jun 10, 2026

Copy link
Copy Markdown

Open in StackBlitz

@tanstack/ai

npm i https://pkg.pr.new/@tanstack/ai@734

@tanstack/ai-anthropic

npm i https://pkg.pr.new/@tanstack/ai-anthropic@734

@tanstack/ai-client

npm i https://pkg.pr.new/@tanstack/ai-client@734

@tanstack/ai-code-mode

npm i https://pkg.pr.new/@tanstack/ai-code-mode@734

@tanstack/ai-code-mode-skills

npm i https://pkg.pr.new/@tanstack/ai-code-mode-skills@734

@tanstack/ai-devtools-core

npm i https://pkg.pr.new/@tanstack/ai-devtools-core@734

@tanstack/ai-elevenlabs

npm i https://pkg.pr.new/@tanstack/ai-elevenlabs@734

@tanstack/ai-event-client

npm i https://pkg.pr.new/@tanstack/ai-event-client@734

@tanstack/ai-fal

npm i https://pkg.pr.new/@tanstack/ai-fal@734

@tanstack/ai-gemini

npm i https://pkg.pr.new/@tanstack/ai-gemini@734

@tanstack/ai-grok

npm i https://pkg.pr.new/@tanstack/ai-grok@734

@tanstack/ai-groq

npm i https://pkg.pr.new/@tanstack/ai-groq@734

@tanstack/ai-isolate-cloudflare

npm i https://pkg.pr.new/@tanstack/ai-isolate-cloudflare@734

@tanstack/ai-isolate-node

npm i https://pkg.pr.new/@tanstack/ai-isolate-node@734

@tanstack/ai-isolate-quickjs

npm i https://pkg.pr.new/@tanstack/ai-isolate-quickjs@734

@tanstack/ai-mcp

npm i https://pkg.pr.new/@tanstack/ai-mcp@734

@tanstack/ai-ollama

npm i https://pkg.pr.new/@tanstack/ai-ollama@734

@tanstack/ai-openai

npm i https://pkg.pr.new/@tanstack/ai-openai@734

@tanstack/ai-openrouter

npm i https://pkg.pr.new/@tanstack/ai-openrouter@734

@tanstack/ai-preact

npm i https://pkg.pr.new/@tanstack/ai-preact@734

@tanstack/ai-react

npm i https://pkg.pr.new/@tanstack/ai-react@734

@tanstack/ai-react-ui

npm i https://pkg.pr.new/@tanstack/ai-react-ui@734

@tanstack/ai-solid

npm i https://pkg.pr.new/@tanstack/ai-solid@734

@tanstack/ai-solid-ui

npm i https://pkg.pr.new/@tanstack/ai-solid-ui@734

@tanstack/ai-svelte

npm i https://pkg.pr.new/@tanstack/ai-svelte@734

@tanstack/ai-utils

npm i https://pkg.pr.new/@tanstack/ai-utils@734

@tanstack/ai-vue

npm i https://pkg.pr.new/@tanstack/ai-vue@734

@tanstack/ai-vue-ui

npm i https://pkg.pr.new/@tanstack/ai-vue-ui@734

@tanstack/openai-base

npm i https://pkg.pr.new/@tanstack/openai-base@734

@tanstack/preact-ai-devtools

npm i https://pkg.pr.new/@tanstack/preact-ai-devtools@734

@tanstack/react-ai-devtools

npm i https://pkg.pr.new/@tanstack/react-ai-devtools@734

@tanstack/solid-ai-devtools

npm i https://pkg.pr.new/@tanstack/solid-ai-devtools@734

commit: a020e86

@tombeckenham tombeckenham left a comment

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.

Nice work on this. Thanks heaps!

@tombeckenham tombeckenham merged commit 570c08a into TanStack:main Jun 10, 2026
10 checks passed
@github-actions github-actions Bot mentioned this pull request Jun 10, 2026
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.

Debug logging: meta payloads dropped on Cloudflare Workers / workerd (ConsoleLogger uses Node-only console.dir)

2 participants