#4834·graphql-js

GraphQL diagnostics_channel tracing publishes non-structured-cloneable payloads in Cloudflare Workers Tail Workers

Author: astanciuCreated Jul 6, 2026Updated Aug 11, 2026

GraphQL.js 17 resolves node:diagnostics_channel at module load and creates graphql:* tracing channels.

In Cloudflare Workers with nodejs_compat and a Tail Worker attached, Cloudflare forwards diagnostics channel messages to Tail Workers as diagnosticsChannelEvents. That forwarding appears to require structured-cloneable payloads.

GraphQL diagnostic contexts include objects like GraphQLSchema, DocumentNode, Source, execution results, resolver args/results, etc. Some of these are not structured-cloneable. In production this causes Cloudflare runtime log errors like:

Failed to publish diagnostics channel message:

The request itself still succeeds; logs get polluted with runtime errors.

Reproduction shape

  1. Deploy a Cloudflare Worker with:
    • compatibility_flags = ["nodejs_compat"]
    • a Tail Worker configured
    • GraphQL.js 17
  2. Execute a GraphQL request through GraphQL Yoga or direct GraphQL.js parse/validate/execute.
  3. Runtime logs repeatedly show:

Failed to publish diagnostics channel message:

This happens even without application-level OpenTelemetry.

Relevant GraphQL.js behavior

graphql/diagnostics.mjs does:

javascript
const dc = resolveDiagnosticsChannel();
export const parseChannel = dc?.tracingChannel('graphql:parse');
export const validateChannel = dc?.tracingChannel('graphql:validate');

and emission sites trace when channel.hasSubscribers is true.

On Cloudflare, Tail forwarding appears to act as a diagnostics subscriber, so tracing is enabled even when the app did not intentionally subscribe to GraphQL diagnostics.

### Expected behavior

GraphQL.js 17 should work in Cloudflare Workers with Tail Workers enabled without runtime diagnostics errors.

Possible fixes:

- expose an official opt-out for GraphQL diagnostics tracing,
- avoid publishing non-structured-cloneable objects by default,
- provide serialization/sanitization hooks,
- or avoid enabling tracing for infrastructure-level diagnostics forwarding.

### Workaround

We patched resolveDiagnosticsChannel() to return undefined, disabling GraphQL diagnostics entirely. That works, but it is brittle and disables useful instrumentation.