What happens
On a server booted with logger: false, core's access-log onResponse hook calls request.log.isLevelEnabled('info'). Fastify's null logger has no isLevelEnabled, so the hook throws on every request, and the aborted hook chain means all downstream plugin onResponse hooks never run. Earlier lifecycle stages (onRequest, preHandler, onSend) are unaffected, which makes the failure look like a plugin bug rather than a host one.
Repro
const fastify = createServer({ logger: false, plugins: [{ id: 'm', module: 'metrics/plugin.js', prefix: '/metrics' }] });
// plugin's addHook('onResponse', ...) never fires; its request counters stay at zero
Workaround: boot with logger: true, logLevel: 'silent'.
Evidence
Found and measured by the out-of-tree Prometheus exporter: https://github.com/JavaScriptSolidServer/plugins/tree/gh-pages/metrics (README, Findings). Both hook-scope experiment orders confirmed the hook chain is fine with logging enabled and dead with logger: false.
Suggested fix
One-line guard in the access-log hook: check typeof request.log.isLevelEnabled === 'function' (or wrap in try/catch, or skip the hook entirely when the logger is disabled).
What happens
On a server booted with
logger: false, core's access-logonResponsehook callsrequest.log.isLevelEnabled('info'). Fastify's null logger has noisLevelEnabled, so the hook throws on every request, and the aborted hook chain means all downstream pluginonResponsehooks never run. Earlier lifecycle stages (onRequest,preHandler,onSend) are unaffected, which makes the failure look like a plugin bug rather than a host one.Repro
Workaround: boot with
logger: true, logLevel: 'silent'.Evidence
Found and measured by the out-of-tree Prometheus exporter: https://github.com/JavaScriptSolidServer/plugins/tree/gh-pages/metrics (README, Findings). Both hook-scope experiment orders confirmed the hook chain is fine with logging enabled and dead with
logger: false.Suggested fix
One-line guard in the access-log hook: check
typeof request.log.isLevelEnabled === 'function'(or wrap in try/catch, or skip the hook entirely when the logger is disabled).