Prerequisites
Fastify version
5.10.0
Plugin version
11.0.2
Node.js version
22.22.2
Operating system
macOS
Operating system version (i.e. 20.04, 11.3, 10)
26.5.2
Description
request.opentelemetry().enabled can return true even when the current request was not instrumented and both span and context are null.
This happens when instrumentation is skipped by ignorePaths, and also when the instrumentation instance is disabled globally. In both cases the request span is not created, but the public request API currently computes enabled only from the route config, roughly equivalent to config.otel !== false.
That makes the runtime value inconsistent with the TypeScript contract for FastifyOtelRequestContext, where enabled: true implies non-null span and context, while enabled: false implies both are null.
Steps to Reproduce
const Fastify = require('fastify')
const FastifyOtelInstrumentation = require('@fastify/otel')
const app = Fastify()
const instrumentation = new FastifyOtelInstrumentation({
ignorePaths: '/health'
})
await app.register(instrumentation.plugin())
app.get('/health', (request) => {
const otel = request.opentelemetry()
console.log(otel.enabled) // true
console.log(otel.span) // null
console.log(otel.context) // null
return 'ok'
})
await app.inject({ method: 'GET', url: '/health' })
The same contract issue can happen when instrumentation is disabled globally:
const app = Fastify()
const instrumentation = new FastifyOtelInstrumentation()
await app.register(instrumentation.plugin())
app.get('/disabled', (request) => {
const otel = request.opentelemetry()
console.log(otel.enabled) // true
console.log(otel.span) // null
console.log(otel.context) // null
return 'ok'
})
instrumentation.disable()
await app.inject({ method: 'GET', url: '/disabled' })
Expected Behavior
When instrumentation is skipped and no request span/context exists, request.opentelemetry() should return a disabled context:
{
enabled: false,
span: null,
context: null
}
Actual Behavior
request.opentelemetry() currently returns:
{
enabled: true,
span: null,
context: null
}
This can cause user code that relies on the discriminated union to crash:
const otel = request.opentelemetry()
if (otel.enabled) {
otel.span.setAttribute('example', 'value')
}
Fix
Compute enabled from the actual instrumentation/request state, not only from route config. It should be true only when instrumentation is enabled, the route is not disabled, and the request actually has a non-null span and context.
Prerequisites
Fastify version
5.10.0
Plugin version
11.0.2
Node.js version
22.22.2
Operating system
macOS
Operating system version (i.e. 20.04, 11.3, 10)
26.5.2
Description
request.opentelemetry().enabledcan returntrueeven when the current request was not instrumented and bothspanandcontextarenull.This happens when instrumentation is skipped by
ignorePaths, and also when the instrumentation instance is disabled globally. In both cases the request span is not created, but the public request API currently computesenabledonly from the route config, roughly equivalent toconfig.otel !== false.That makes the runtime value inconsistent with the TypeScript contract for
FastifyOtelRequestContext, whereenabled: trueimplies non-nullspanandcontext, whileenabled: falseimplies both arenull.Steps to Reproduce
The same contract issue can happen when instrumentation is disabled globally:
Expected Behavior
When instrumentation is skipped and no request span/context exists,
request.opentelemetry()should return a disabled context:Actual Behavior
request.opentelemetry()currently returns:This can cause user code that relies on the discriminated union to crash:
Fix
Compute
enabledfrom the actual instrumentation/request state, not only from route config. It should be true only when instrumentation is enabled, the route is not disabled, and the request actually has a non-null span and context.