graphql / graphql/graphql-js

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

Open
#4,834 5 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
20.3k
Forks
2.1k
Avg merge
44m
Merged PRs (30d)
6

Description

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:

```js
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.

Contributor guide

Open the contributing guide

Research direction

Start with graphql/diagnostics.mjs and resolveDiagnosticsChannel(), then reproduce the listed Cloudflare Worker setup with nodejs_compat, a Tail Worker, and a GraphQL parse/validate/execute request. Compare the tracing emission sites and the proposed opt-out, sanitization, and serialization approaches; done means GraphQL.js works without Cloudflare runtime diagnostics errors while useful instrumentation remains possible.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, typescript
Domain
backend-api-design, observability-sre
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.