Skip to content

fix(fastify): guard error publishing against re-entrant recursion#8788

Merged
pabloerhard merged 1 commit into
masterfrom
BridgeAR/2026-06-03-fastify-error-recursion
Jun 5, 2026
Merged

fix(fastify): guard error publishing against re-entrant recursion#8788
pabloerhard merged 1 commit into
masterfrom
BridgeAR/2026-06-03-fastify-error-recursion

Conversation

@BridgeAR

@BridgeAR BridgeAR commented Jun 3, 2026

Copy link
Copy Markdown
Member

Summary

A subscriber on the public apm:fastify:middleware:error channel that re-enters a wrapped hook while handling the error republishes through publishError, which republishes again, until the stack overflows (RangeError: Maximum call stack size exceeded during plugin registration).

Two coordinated pieces close it:

  1. publishError tracks an in-flight flag and drops the re-entrant publish instead of recursing; try/finally clears it even when a subscriber throws.
  2. reply.send(error) routes through publishError rather than a bare errorChannel.publish, so the response-error path is guarded too.

Drive-by

  • preValidation forwards done() when parsingContexts holds no entry, instead of dereferencing a missing ctx in processInContext (TypeError when a param channel has a subscriber but onRequest took the fast path).

Test plan

  • packages/datadog-instrumentations/test/fastify.spec.js re-entrancy regression test fails without the guard (depth 51) and passes with it.

This PR addresses: #8783

A subscriber on the public apm:fastify:middleware:error channel that
re-enters a wrapped hook while handling the error republishes through
publishError, which republishes again, until the stack overflows
(RangeError: Maximum call stack size exceeded during plugin registration).

Two coordinated pieces close it:

1. publishError tracks an in-flight flag and drops the re-entrant publish
   instead of recursing; try/finally clears it even when a subscriber throws.
2. reply.send(error) routes through publishError rather than a bare
   errorChannel.publish, so the response-error path is guarded too.

Drive-by fix:

* preValidation forwards done() when parsingContexts holds no entry, instead
  of dereferencing a missing ctx in processInContext (TypeError when a param
  channel has a subscriber but onRequest took the fast path).
@dd-octo-sts

dd-octo-sts Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Overall package size

Self size: 6.17 MB
Deduped: 7.21 MB
No deduping: 7.21 MB

Dependency sizes | name | version | self size | total size | |------|---------|-----------|------------| | import-in-the-middle | 3.0.1 | 82.56 kB | 817.39 kB | | opentracing | 0.14.7 | 194.81 kB | 194.81 kB | | dc-polyfill | 0.1.11 | 25.74 kB | 25.74 kB |

🤖 This report was automatically generated by heaviest-objects-in-the-universe

@codecov

codecov Bot commented Jun 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.67%. Comparing base (a75867c) to head (de99867).
⚠️ Report is 16 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #8788      +/-   ##
==========================================
+ Coverage   92.66%   92.67%   +0.01%     
==========================================
  Files         862      862              
  Lines       49347    49350       +3     
  Branches     9327     9326       -1     
==========================================
+ Hits        45727    45737      +10     
+ Misses       3620     3613       -7     
Flag Coverage Δ
aiguard-integration-active 41.29% <ø> (ø)
aiguard-integration-latest 41.31% <ø> (ø)
aiguard-integration-maintenance 41.39% <ø> (+0.13%) ⬆️
aiguard-macos 33.30% <ø> (-0.08%) ⬇️
aiguard-ubuntu 33.46% <ø> (-0.08%) ⬇️
aiguard-windows 33.12% <ø> (-0.08%) ⬇️
apm-capabilities-tracing-macos 48.54% <ø> (ø)
apm-capabilities-tracing-ubuntu-active 48.53% <ø> (ø)
apm-capabilities-tracing-ubuntu-latest 48.53% <ø> (ø)
apm-capabilities-tracing-ubuntu-maintenance 48.58% <ø> (-0.19%) ⬇️
apm-capabilities-tracing-ubuntu-oldest 48.77% <ø> (+0.18%) ⬆️
apm-capabilities-tracing-windows 48.52% <ø> (+0.17%) ⬆️
apm-integrations-aerospike-18-gte.5.2.0 33.22% <ø> (-0.08%) ⬇️
apm-integrations-aerospike-20-gte.5.5.0 33.24% <ø> (-0.08%) ⬇️
apm-integrations-aerospike-22-gte.5.12.1 33.25% <ø> (-0.08%) ⬇️
apm-integrations-aerospike-22-gte.6.0.0 33.25% <ø> (-0.08%) ⬇️
apm-integrations-aerospike-eol- 33.15% <ø> (-0.08%) ⬇️
apm-integrations-child-process 34.17% <ø> (-0.08%) ⬇️
apm-integrations-confluentinc-kafka-javascript-18 40.26% <ø> (-0.08%) ⬇️
apm-integrations-confluentinc-kafka-javascript-20 40.27% <ø> (-0.08%) ⬇️
apm-integrations-confluentinc-kafka-javascript-22 40.28% <ø> (-0.08%) ⬇️
apm-integrations-confluentinc-kafka-javascript-24 40.17% <ø> (-0.08%) ⬇️
apm-integrations-couchbase-18 33.24% <ø> (-0.08%) ⬇️
apm-integrations-couchbase-eol 33.28% <ø> (-0.08%) ⬇️
apm-integrations-dns 33.16% <ø> (-0.08%) ⬇️
apm-integrations-elasticsearch 34.19% <ø> (-0.08%) ⬇️
apm-integrations-http-latest 41.43% <ø> (-0.09%) ⬇️
apm-integrations-http-maintenance 41.52% <ø> (-0.07%) ⬇️
apm-integrations-http-oldest 41.45% <ø> (-0.07%) ⬇️
apm-integrations-http2 38.74% <ø> (+0.08%) ⬆️
apm-integrations-kafkajs-latest 40.36% <ø> (+0.02%) ⬆️
apm-integrations-kafkajs-oldest 40.45% <ø> (-0.08%) ⬇️
apm-integrations-net 33.87% <ø> (-0.08%) ⬇️
apm-integrations-next-11.1.4 36.43% <ø> (ø)
apm-integrations-next-12.3.7 36.43% <ø> (ø)
apm-integrations-next-13.0.0 29.18% <ø> (-0.08%) ⬇️
apm-integrations-next-13.2.0 29.18% <ø> (-0.08%) ⬇️
apm-integrations-next-13.5.11 29.31% <ø> (-0.08%) ⬇️
apm-integrations-next-14.0.0 29.24% <ø> (-0.08%) ⬇️
apm-integrations-next-14.2.35 29.24% <ø> (-0.08%) ⬇️
apm-integrations-next-14.2.6 29.24% <ø> (-0.08%) ⬇️
apm-integrations-next-14.2.7 29.24% <ø> (-0.08%) ⬇️
apm-integrations-next-15.0.0 29.24% <ø> (-0.08%) ⬇️
apm-integrations-next-15.4.0 29.31% <ø> (-0.08%) ⬇️
apm-integrations-oracledb 34.08% <ø> (-0.08%) ⬇️
apm-integrations-prisma-18-gte.6.16.0.and.lt.7.0.0 34.59% <ø> (-0.08%) ⬇️
apm-integrations-prisma-latest-all 34.29% <ø> (-0.08%) ⬇️
apm-integrations-restify 35.28% <ø> (-0.08%) ⬇️
apm-integrations-sharedb 32.56% <ø> (-0.08%) ⬇️
apm-integrations-tedious 33.48% <ø> (-0.08%) ⬇️
appsec-express 51.36% <ø> (-0.06%) ⬇️
appsec-fastify 48.09% <100.00%> (-0.05%) ⬇️
appsec-graphql 48.07% <44.44%> (-0.07%) ⬇️
appsec-integration-active 36.14% <33.33%> (-0.01%) ⬇️
appsec-integration-latest 36.14% <33.33%> (-0.01%) ⬇️
appsec-integration-maintenance 36.20% <33.33%> (-0.01%) ⬇️
appsec-integration-oldest ?
appsec-kafka 40.53% <ø> (-0.12%) ⬇️
appsec-ldapjs 39.93% <ø> (-0.07%) ⬇️
appsec-lodash 39.95% <ø> (-0.07%) ⬇️
appsec-macos 57.30% <ø> (-0.08%) ⬇️
appsec-mongodb-core 44.17% <ø> (-0.07%) ⬇️
appsec-mongoose 45.03% <ø> (-0.06%) ⬇️
appsec-mysql 47.31% <ø> (-0.06%) ⬇️
appsec-next-latest-11.1.4 27.46% <ø> (-0.07%) ⬇️
appsec-next-latest-12.3.7 27.55% <ø> (ø)
appsec-next-latest-13.0.0 29.25% <ø> (-0.08%) ⬇️
appsec-next-latest-13.2.0 29.28% <ø> (-0.08%) ⬇️
appsec-next-latest-13.5.11 29.37% <ø> (-0.08%) ⬇️
appsec-next-latest-14.0.0 29.30% <ø> (-0.08%) ⬇️
appsec-next-latest-14.2.35 29.30% <ø> (-0.08%) ⬇️
appsec-next-latest-14.2.6 29.30% <ø> (-0.08%) ⬇️
appsec-next-latest-14.2.7 29.30% <ø> (-0.08%) ⬇️
appsec-next-latest-15.0.0 29.30% <ø> (-0.08%) ⬇️
appsec-next-latest-latest 29.31% <ø> (-0.08%) ⬇️
appsec-next-oldest-11.1.4 27.51% <ø> (-0.08%) ⬇️
appsec-next-oldest-12.3.7 29.31% <ø> (-0.08%) ⬇️
appsec-next-oldest-13.0.0 29.31% <ø> (-0.08%) ⬇️
appsec-next-oldest-13.2.0 29.58% <ø> (-0.08%) ⬇️
appsec-next-oldest-13.5.11 29.68% <ø> (-0.08%) ⬇️
appsec-next-oldest-14.0.0 29.62% <ø> (-0.08%) ⬇️
appsec-next-oldest-14.2.35 29.62% <ø> (-0.08%) ⬇️
appsec-next-oldest-14.2.6 29.62% <ø> (-0.08%) ⬇️
appsec-next-oldest-14.2.7 29.62% <ø> (-0.08%) ⬇️
appsec-next-oldest-15.0.0 29.62% <ø> (-0.08%) ⬇️
appsec-next-oldest-latest 27.76% <ø> (ø)
appsec-node-serialize 39.26% <ø> (-0.07%) ⬇️
appsec-passport 42.87% <ø> (-0.07%) ⬇️
appsec-postgres ?
appsec-sourcing 38.67% <ø> (-0.07%) ⬇️
appsec-stripe 40.61% <ø> (-0.07%) ⬇️
appsec-template 39.50% <ø> (-0.07%) ⬇️
appsec-ubuntu 57.42% <ø> (-0.06%) ⬇️
appsec-windows 57.22% <ø> (-0.06%) ⬇️
debugger-ubuntu-active 43.77% <33.33%> (-0.01%) ⬇️
debugger-ubuntu-latest 43.77% <33.33%> (-0.01%) ⬇️
debugger-ubuntu-maintenance ?
debugger-ubuntu-oldest 43.96% <33.33%> (-0.26%) ⬇️
instrumentations-instrumentation-ai 42.24% <ø> (ø)
instrumentations-instrumentation-aws-sdk 44.55% <ø> (ø)
instrumentations-instrumentation-bluebird 27.59% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-body-parser 35.78% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-child_process 33.54% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-cookie-parser 29.50% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-couchbase-18 45.68% <ø> (ø)
instrumentations-instrumentation-couchbase-eol 45.68% <ø> (ø)
instrumentations-instrumentation-crypto 27.65% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-express 29.70% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-express-mongo-sanitize 29.61% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-express-multi-version 41.41% <ø> (ø)
instrumentations-instrumentation-express-session 35.56% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-fastify 47.57% <100.00%> (+1.25%) ⬆️
instrumentations-instrumentation-fetch 44.72% <ø> (ø)
instrumentations-instrumentation-fs 27.29% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-generic-pool 27.11% <ø> (ø)
instrumentations-instrumentation-hono 28.81% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-http 35.22% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-http-client-options 37.76% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-kafkajs 48.67% <ø> (ø)
instrumentations-instrumentation-knex 27.58% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-light-my-request 35.41% <33.33%> (-0.08%) ⬇️
instrumentations-instrumentation-mongoose 28.69% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-multer 35.45% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-mysql2 33.51% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-openai-aiguard 47.27% <ø> (ø)
instrumentations-instrumentation-otel-sdk-trace 25.23% <ø> (ø)
instrumentations-instrumentation-passport 39.33% <ø> (-0.07%) ⬇️
instrumentations-instrumentation-passport-http 39.02% <ø> (-0.07%) ⬇️
instrumentations-instrumentation-passport-local 39.48% <ø> (-0.07%) ⬇️
instrumentations-instrumentation-pg 33.23% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-promise 27.54% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-promise-js 27.55% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-q 27.58% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-router 42.77% <ø> (ø)
instrumentations-instrumentation-stripe 28.07% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-url 27.48% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-when 27.56% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-zlib 27.53% <ø> (-0.08%) ⬇️
instrumentations-integration-esbuild-0.16.12-active 18.43% <11.11%> (+<0.01%) ⬆️
instrumentations-integration-esbuild-0.16.12-latest ?
instrumentations-integration-esbuild-0.16.12-maintenance 18.46% <11.11%> (+<0.01%) ⬆️
instrumentations-integration-esbuild-0.16.12-oldest 18.45% <11.11%> (+<0.01%) ⬆️
instrumentations-integration-esbuild-latest-active ?
instrumentations-integration-esbuild-latest-latest 18.43% <11.11%> (+<0.01%) ⬆️
instrumentations-integration-esbuild-latest-maintenance 18.46% <11.11%> (+<0.01%) ⬆️
instrumentations-integration-esbuild-latest-oldest 18.45% <11.11%> (+<0.01%) ⬆️
llmobs-ai 34.98% <ø> (-0.07%) ⬇️
llmobs-anthropic 36.70% <ø> (-0.08%) ⬇️
llmobs-bedrock 36.15% <ø> (-0.07%) ⬇️
llmobs-google-genai 35.74% <ø> (-0.07%) ⬇️
llmobs-langchain 34.60% <ø> (-0.06%) ⬇️
llmobs-openai-latest 39.12% <ø> (-0.07%) ⬇️
llmobs-openai-oldest ?
llmobs-sdk-active 43.51% <ø> (-0.08%) ⬇️
llmobs-sdk-latest 43.51% <ø> (-0.08%) ⬇️
llmobs-sdk-maintenance 43.61% <ø> (-0.08%) ⬇️
llmobs-sdk-oldest ?
llmobs-vertex-ai 35.74% <ø> (-0.08%) ⬇️
master-coverage 92.67% <100.00%> (?)
openfeature-macos 37.62% <ø> (ø)
openfeature-ubuntu 37.76% <ø> (-0.01%) ⬇️
openfeature-unit-active 50.24% <ø> (ø)
openfeature-unit-latest 50.24% <ø> (ø)
openfeature-unit-maintenance 50.60% <ø> (ø)
openfeature-unit-oldest 50.60% <ø> (ø)
openfeature-windows 37.44% <ø> (-0.06%) ⬇️
platform-core 45.95% <ø> (ø)
platform-esbuild 46.60% <ø> (ø)
platform-instrumentations-misc 30.57% <ø> (ø)
platform-integration-active 46.83% <33.33%> (-0.06%) ⬇️
platform-integration-latest 46.86% <33.33%> (-0.02%) ⬇️
platform-integration-maintenance 46.97% <33.33%> (+0.03%) ⬆️
platform-integration-oldest 47.13% <33.33%> (-0.01%) ⬇️
platform-shimmer 47.03% <ø> (ø)
platform-unit-guardrails 44.00% <ø> (ø)
platform-webpack 17.96% <11.11%> (+<0.01%) ⬆️
plugins-axios 35.55% <ø> (-0.02%) ⬇️
plugins-azure-cosmos 36.02% <ø> (-0.08%) ⬇️
plugins-azure-event-hubs 34.84% <ø> (ø)
plugins-azure-service-bus 35.32% <ø> (ø)
plugins-body-parser 36.54% <ø> (ø)
plugins-bullmq 39.16% <ø> (-0.08%) ⬇️
plugins-cassandra 33.69% <ø> (-0.08%) ⬇️
plugins-cookie 40.22% <ø> (ø)
plugins-cookie-parser 40.05% <ø> (ø)
plugins-crypto 42.30% <ø> (ø)
plugins-dd-trace-api 33.39% <ø> (-0.08%) ⬇️
plugins-express-mongo-sanitize 40.11% <ø> (ø)
plugins-express-session 39.97% <ø> (ø)
plugins-fastify 37.87% <100.00%> (-0.06%) ⬇️
plugins-fetch 34.13% <ø> (-0.08%) ⬇️
plugins-fs 33.79% <ø> (-0.08%) ⬇️
plugins-generic-pool 39.53% <ø> (ø)
plugins-google-cloud-pubsub 41.55% <ø> (-0.09%) ⬇️
plugins-grpc 36.63% <ø> (?)
plugins-handlebars 40.11% <ø> (ø)
plugins-hapi 35.69% <ø> (-0.08%) ⬇️
plugins-hono 36.02% <ø> (-0.08%) ⬇️
plugins-ioredis 34.28% <ø> (-0.06%) ⬇️
plugins-jest 27.08% <ø> (ø)
plugins-knex 39.59% <ø> (ø)
plugins-langgraph 32.41% <ø> (-0.08%) ⬇️
plugins-ldapjs 38.55% <ø> (ø)
plugins-light-my-request 39.68% <ø> (ø)
plugins-limitd-client 27.90% <ø> (-0.08%) ⬇️
plugins-lodash 39.71% <ø> (ø)
plugins-mariadb 35.23% <ø> (-0.08%) ⬇️
plugins-memcached 33.77% <ø> (-0.08%) ⬇️
plugins-microgateway-core 34.79% <ø> (-0.08%) ⬇️
plugins-modelcontextprotocol-sdk 32.37% <ø> (-0.08%) ⬇️
plugins-moleculer 36.69% <ø> (-0.08%) ⬇️
plugins-mongodb 35.83% <ø> (-0.17%) ⬇️
plugins-mongodb-core 35.52% <ø> (-0.08%) ⬇️
plugins-mongoose 34.40% <ø> (-0.08%) ⬇️
plugins-multer 40.02% <ø> (ø)
plugins-mysql 34.70% <ø> (-0.08%) ⬇️
plugins-mysql2 ?
plugins-nats 36.43% <ø> (-0.08%) ⬇️
plugins-node-serialize 40.25% <ø> (ø)
plugins-opensearch 33.64% <ø> (-0.08%) ⬇️
plugins-passport-http 39.84% <ø> (ø)
plugins-pino 29.82% <ø> (-0.08%) ⬇️
plugins-postgres 34.54% <ø> (-0.08%) ⬇️
plugins-process 42.30% <ø> (ø)
plugins-pug 40.22% <ø> (ø)
plugins-redis ?
plugins-router 38.13% <ø> (-0.08%) ⬇️
plugins-sequelize 39.49% <ø> (ø)
plugins-test-and-upstream-amqp10 33.92% <ø> (-0.08%) ⬇️
plugins-test-and-upstream-amqplib 39.15% <ø> (-0.27%) ⬇️
plugins-test-and-upstream-apollo ?
plugins-test-and-upstream-avsc 33.80% <ø> (-0.08%) ⬇️
plugins-test-and-upstream-bunyan 29.03% <ø> (-0.08%) ⬇️
plugins-test-and-upstream-connect 36.37% <ø> (?)
plugins-test-and-upstream-graphql 36.12% <ø> (-0.08%) ⬇️
plugins-test-and-upstream-koa 35.87% <ø> (-0.08%) ⬇️
plugins-test-and-upstream-protobufjs 34.04% <ø> (-0.08%) ⬇️
plugins-test-and-upstream-rhea 39.28% <ø> (-0.08%) ⬇️
plugins-undici 34.62% <ø> (-0.08%) ⬇️
plugins-url 42.30% <ø> (ø)
plugins-valkey 33.87% <ø> (+0.06%) ⬆️
plugins-vm 42.30% <ø> (ø)
plugins-winston 29.68% <ø> (-0.08%) ⬇️
plugins-ws 37.14% <ø> (-0.08%) ⬇️
profiling-macos 43.26% <ø> (-0.07%) ⬇️
profiling-ubuntu 43.76% <ø> (-0.02%) ⬇️
profiling-windows 40.96% <ø> (-0.12%) ⬇️
serverless-aws-sdk-latest-aws-sdk 33.25% <ø> (-0.08%) ⬇️
serverless-aws-sdk-latest-bedrockruntime ?
serverless-aws-sdk-latest-client ?
serverless-aws-sdk-latest-dynamodb 33.98% <ø> (-0.07%) ⬇️
serverless-aws-sdk-latest-eventbridge 27.04% <ø> (-0.07%) ⬇️
serverless-aws-sdk-latest-kinesis 37.15% <ø> (-0.07%) ⬇️
serverless-aws-sdk-latest-lambda 34.51% <ø> (-0.07%) ⬇️
serverless-aws-sdk-latest-s3 32.38% <ø> (-0.07%) ⬇️
serverless-aws-sdk-latest-serverless-peer-service 39.44% <ø> (-0.08%) ⬇️
serverless-aws-sdk-latest-sns 38.29% <ø> (-0.07%) ⬇️
serverless-aws-sdk-latest-sqs 37.77% <ø> (-0.07%) ⬇️
serverless-aws-sdk-latest-stepfunctions 33.08% <ø> (-0.07%) ⬇️
serverless-aws-sdk-latest-util 46.35% <ø> (ø)
serverless-aws-sdk-oldest-aws-sdk 33.36% <ø> (-0.06%) ⬇️
serverless-aws-sdk-oldest-bedrockruntime 32.14% <ø> (-0.07%) ⬇️
serverless-aws-sdk-oldest-client 36.50% <ø> (ø)
serverless-aws-sdk-oldest-dynamodb 34.08% <ø> (-0.13%) ⬇️
serverless-aws-sdk-oldest-eventbridge 27.12% <ø> (-0.07%) ⬇️
serverless-aws-sdk-oldest-kinesis 37.33% <ø> (-0.07%) ⬇️
serverless-aws-sdk-oldest-lambda 34.62% <ø> (-0.07%) ⬇️
serverless-aws-sdk-oldest-s3 32.52% <ø> (-0.07%) ⬇️
serverless-aws-sdk-oldest-serverless-peer-service 39.53% <ø> (-0.08%) ⬇️
serverless-aws-sdk-oldest-sns 38.39% <ø> (-0.07%) ⬇️
serverless-aws-sdk-oldest-sqs ?
serverless-aws-sdk-oldest-stepfunctions 33.18% <ø> (-0.07%) ⬇️
serverless-aws-sdk-oldest-util 47.11% <ø> (ø)
serverless-azure-durable-functions 36.82% <ø> (ø)
serverless-azure-functions-eventhubs 38.43% <ø> (ø)
serverless-azure-functions-servicebus 38.49% <ø> (ø)
serverless-lambda 34.57% <ø> (-0.10%) ⬇️
test-optimization-cucumber-latest-7.0.0 50.15% <ø> (+0.01%) ⬆️
test-optimization-cucumber-latest-latest 52.80% <ø> (+0.10%) ⬆️
test-optimization-cucumber-oldest-7.0.0 50.23% <ø> (+0.11%) ⬆️
test-optimization-cypress-latest-12.0.0-commonJS 49.54% <ø> (+0.07%) ⬆️
test-optimization-cypress-latest-12.0.0-esm 49.57% <ø> (+0.07%) ⬆️
test-optimization-cypress-latest-14.5.4-commonJS 49.38% <ø> (+0.07%) ⬆️
test-optimization-cypress-latest-14.5.4-esm 48.65% <ø> (-0.80%) ⬇️
test-optimization-cypress-latest-latest-commonJS 49.87% <ø> (+0.07%) ⬆️
test-optimization-cypress-latest-latest-esm 49.90% <ø> (+0.07%) ⬆️
test-optimization-cypress-oldest-12.0.0-commonJS 49.62% <ø> (+0.07%) ⬆️
test-optimization-cypress-oldest-12.0.0-esm 49.65% <ø> (+0.07%) ⬆️
test-optimization-cypress-oldest-14.5.4-commonJS 49.47% <ø> (+0.07%) ⬆️
test-optimization-cypress-oldest-14.5.4-esm 49.50% <ø> (+0.07%) ⬆️
test-optimization-jest-latest-latest 55.49% <ø> (+0.08%) ⬆️
test-optimization-jest-latest-oldest 54.33% <ø> (+0.08%) ⬆️
test-optimization-jest-oldest-latest 55.54% <ø> (+0.08%) ⬆️
test-optimization-jest-oldest-oldest 54.41% <ø> (+0.08%) ⬆️
test-optimization-mocha-latest-latest 53.68% <ø> (+0.08%) ⬆️
test-optimization-mocha-latest-oldest 51.36% <ø> (+0.08%) ⬆️
test-optimization-mocha-oldest-latest 53.79% <ø> (+0.08%) ⬆️
test-optimization-mocha-oldest-oldest 51.34% <ø> (+0.08%) ⬆️
test-optimization-playwright-latest-latest-playwright-active-test-span 44.40% <ø> (+0.27%) ⬆️
test-optimization-playwright-latest-latest-playwright-atr 43.06% <ø> (+0.10%) ⬆️
test-optimization-playwright-latest-latest-playwright-efd 43.47% <ø> (+0.09%) ⬆️
test-optimization-playwright-latest-latest-playwright-final-status 43.51% <ø> (+0.10%) ⬆️
test-optimization-playwright-latest-latest-playwright-impacted-tests 43.00% <ø> (ø)
test-optimization-playwright-latest-latest-playwright-reporting 43.11% <ø> (+0.08%) ⬆️
test-optimization-playwright-latest-latest-playwright-test-management 44.66% <ø> (+0.07%) ⬆️
test-optimization-playwright-latest-oldest-playwright-active-test-span 44.22% <ø> (+0.27%) ⬆️
test-optimization-playwright-latest-oldest-playwright-atr 43.15% <ø> (+0.10%) ⬆️
test-optimization-playwright-latest-oldest-playwright-efd 43.38% <ø> (+0.09%) ⬆️
test-optimization-playwright-latest-oldest-playwright-final-status ?
test-optimization-playwright-latest-oldest-playwright-impacted-tests 42.92% <ø> (ø)
test-optimization-playwright-latest-oldest-playwright-reporting ?
test-optimization-playwright-latest-oldest-playwright-test-management 44.63% <ø> (+0.10%) ⬆️
test-optimization-playwright-oldest-latest-playwright-active-test-span 44.48% <ø> (+0.08%) ⬆️
test-optimization-playwright-oldest-latest-playwright-atr 43.14% <ø> (+0.08%) ⬆️
test-optimization-playwright-oldest-latest-playwright-efd 43.53% <ø> (+0.09%) ⬆️
test-optimization-playwright-oldest-latest-playwright-final-status 43.62% <ø> (+0.09%) ⬆️
test-optimization-playwright-oldest-latest-playwright-impacted-tests 43.08% <ø> (ø)
test-optimization-playwright-oldest-latest-playwright-reporting 43.16% <ø> (+0.08%) ⬆️
test-optimization-playwright-oldest-latest-playwright-test-management 44.76% <ø> (+0.09%) ⬆️
test-optimization-playwright-oldest-oldest-playwright-active-test-span 44.30% <ø> (+0.27%) ⬆️
test-optimization-playwright-oldest-oldest-playwright-atr 43.23% <ø> (+0.10%) ⬆️
test-optimization-playwright-oldest-oldest-playwright-efd 43.46% <ø> (+0.09%) ⬆️
test-optimization-playwright-oldest-oldest-playwright-final-status 43.56% <ø> (+0.11%) ⬆️
test-optimization-playwright-oldest-oldest-playwright-impacted-tests ?
test-optimization-playwright-oldest-oldest-playwright-reporting 42.99% <ø> (+0.09%) ⬆️
test-optimization-playwright-oldest-oldest-playwright-test-management 44.72% <ø> (+0.10%) ⬆️
test-optimization-selenium-latest 45.37% <ø> (+0.06%) ⬆️
test-optimization-selenium-oldest 45.23% <ø> (+0.07%) ⬆️
test-optimization-testopt-active 48.49% <ø> (+0.12%) ⬆️
test-optimization-testopt-latest 48.49% <ø> (+0.12%) ⬆️
test-optimization-testopt-maintenance 48.50% <ø> (+0.13%) ⬆️
test-optimization-testopt-oldest 49.60% <ø> (+0.10%) ⬆️
test-optimization-vitest-latest 50.91% <ø> (+0.10%) ⬆️
test-optimization-vitest-oldest 48.11% <ø> (+0.97%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@datadog-prod-us1-5

datadog-prod-us1-5 Bot commented Jun 3, 2026

Copy link
Copy Markdown

Tests

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

🎯 Code Coverage (details)
Patch Coverage: 100.00%
Overall Coverage: 86.51% (-0.00%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: de99867 | Docs | Datadog PR Page | Give us feedback!

@pr-commenter

pr-commenter Bot commented Jun 3, 2026

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-06-03 23:47:29

Comparing candidate commit de99867 in PR branch BridgeAR/2026-06-03-fastify-error-recursion with baseline commit a75867c in branch master.

Found 0 performance improvements and 1 performance regressions! Performance is the same for 1443 metrics, 23 unstable metrics.

scenario:spans-finish-later-20

  • 🟥 instructions [+1.1G instructions; +2.4G instructions] or [+5.709%; +12.420%]

@BridgeAR
BridgeAR marked this pull request as ready for review June 5, 2026 13:13
@BridgeAR
BridgeAR requested a review from a team as a code owner June 5, 2026 13:13
@BridgeAR
BridgeAR requested review from bojbrook and removed request for a team June 5, 2026 13:13

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: de998676a8

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

// No stored context means the onRequest/preParsing fast path ran (no error /
// cookie / callback subscribers), so there is nothing to publish on; forward
// `done` instead of dereferencing a missing ctx in processInContext.
if (!ctx) return done()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve parser channels without a stored context

In the missing-context case this now returns before processInContext, but AppSec and IAST subscribe directly to the Fastify body/query/path channels (packages/dd-trace/src/appsec/index.js and .../iast/taint-tracking/plugin.js). When Fastify reaches preValidation without an entry in parsingContexts and any of those subscribers are enabled, this skips publishing the request body/query/params entirely, so WAF checks, aborts, and tainting are silently bypassed for that request; the crash fix should synthesize a minimal { req, res } context and continue through the parser publishing path instead of dropping it.

Useful? React with 👍 / 👎.

@pabloerhard
pabloerhard merged commit bdfda44 into master Jun 5, 2026
799 checks passed
@pabloerhard
pabloerhard deleted the BridgeAR/2026-06-03-fastify-error-recursion branch June 5, 2026 13:59
dd-octo-sts Bot pushed a commit that referenced this pull request Jun 6, 2026
)

A subscriber on the public apm:fastify:middleware:error channel that
re-enters a wrapped hook while handling the error republishes through
publishError, which republishes again, until the stack overflows
(RangeError: Maximum call stack size exceeded during plugin registration).

Two coordinated pieces close it:

1. publishError tracks an in-flight flag and drops the re-entrant publish
   instead of recursing; try/finally clears it even when a subscriber throws.
2. reply.send(error) routes through publishError rather than a bare
   errorChannel.publish, so the response-error path is guarded too.

Drive-by fix:

* preValidation forwards done() when parsingContexts holds no entry, instead
  of dereferencing a missing ctx in processInContext (TypeError when a param
  channel has a subscriber but onRequest took the fast path).
@dd-octo-sts dd-octo-sts Bot mentioned this pull request Jun 6, 2026
BridgeAR added a commit that referenced this pull request Jun 11, 2026
)

A subscriber on the public apm:fastify:middleware:error channel that
re-enters a wrapped hook while handling the error republishes through
publishError, which republishes again, until the stack overflows
(RangeError: Maximum call stack size exceeded during plugin registration).

Two coordinated pieces close it:

1. publishError tracks an in-flight flag and drops the re-entrant publish
   instead of recursing; try/finally clears it even when a subscriber throws.
2. reply.send(error) routes through publishError rather than a bare
   errorChannel.publish, so the response-error path is guarded too.

Drive-by fix:

* preValidation forwards done() when parsingContexts holds no entry, instead
  of dereferencing a missing ctx in processInContext (TypeError when a param
  channel has a subscriber but onRequest took the fast path).
tlhunter pushed a commit that referenced this pull request Jun 18, 2026
)

A subscriber on the public apm:fastify:middleware:error channel that
re-enters a wrapped hook while handling the error republishes through
publishError, which republishes again, until the stack overflows
(RangeError: Maximum call stack size exceeded during plugin registration).

Two coordinated pieces close it:

1. publishError tracks an in-flight flag and drops the re-entrant publish
   instead of recursing; try/finally clears it even when a subscriber throws.
2. reply.send(error) routes through publishError rather than a bare
   errorChannel.publish, so the response-error path is guarded too.

Drive-by fix:

* preValidation forwards done() when parsingContexts holds no entry, instead
  of dereferencing a missing ctx in processInContext (TypeError when a param
  channel has a subscriber but onRequest took the fast path).
BridgeAR added a commit that referenced this pull request Jun 27, 2026
… hook rejections

Fastify boots through avvio, whose `_encapsulateThreeParam` re-invokes an
encapsulated hook after it throws. The same error object rides every re-drive,
and the wrapped hook republishes it on `apm:fastify:middleware:error` each time.
The in-flight boolean added in #8788 only blocks a publish nested inside another
publish; a sequential re-drive runs after the publish returned and its `finally`
cleared the flag, so every re-drive publishes again, the channel subscriber
recurses, and boot dies with `RangeError: Maximum call stack size exceeded`. A
persistent `DatadogRaspAbortError` (appsec RASP) or the boot deprecation warning
is the error that rides the loop.

1. `createErrorPublisher` keeps the boolean for nested re-entry and remembers the
   last published error. The re-drive re-throws the one caught error on every
   hop, so a single reference compare against the previous publish terminates the
   loop where the boolean cannot. This costs one comparison per publish rather
   than a per-publish set lookup, and it does not mutate the error. A distinct
   error still reaches subscribers; only a re-drive alternating two distinct
   persistent errors stays uncollapsed, which is not a shape fastify produces.
2. `invokeHookWithContext`'s async branch returned `publishError(ctx)`, i.e.
   `ctx.error`, from the `.catch` handler, which resolves the promise with the
   error and silently swallows the rejection. It now publishes and re-throws so
   the rejection keeps propagating. The synchronous branch is decoupled the same
   way: publish, then throw the original error rather than throwing the
   publisher's return value.

Fixes: #9099
Refs: #8783
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RangeError: Maximum call stack size exceeded in Fastify instrumentation on 5.106.0

2 participants