How to fix Error: FST_ERR_HOOK_TIMEOUT: Hook has exceeded the timeout limit in Node.js

Node.jsINTERMEDIATEHIGHUpdated Dec 9, 2025· 138 views

The FST_ERR_HOOK_TIMEOUT error occurs when a Fastify hook (onRequest, onSend, etc.) takes longer than the allowed timeout to complete. This error indicates that your hook is either performing long-running operations or is stuck in an infinite loop. Resolving this requires optimizing the hook code or adjusting timeout configuration.

Quick fix

Fixes FST_ERR_HOOK_TIMEOUT

fastify.addHook('onRequest', async (request, reply) => {
  // This is an 'onRequest' hook
});

fastify.addHook('preHandler', async (request, reply) => {
  // This is a 'preHandler' hook
});
  1. Identify which hook is timing out
  2. Check for synchronous blocking operations
  3. Check for infinite loops or missing conditions
  4. Optimize slow database or API calls
node.js — error
fastify.addHook('onRequest', async (request, reply) => {
// This is an 'onRequest' hook
});
fastify.addHook('preHandler', async (request, reply) => {
// This is a 'preHandler' hook
});
Error: FST_ERR_HOOK_TIMEOUT: Hook has exceeded the timeout limit

What this error means

Fastify enforces timeout limits on hooks to prevent them from hanging indefinitely and blocking request processing. Hooks are middleware-like functions that execute at specific lifecycle points (onRequest, preValidation, preHandler, onSend, etc.). When a hook exceeds its configured timeout threshold without completing, Fastify immediately terminates the hook execution and throws this error. This is a safety mechanism to prevent one slow or broken hook from causing your entire application to hang. The error signals that you have a performance problem or logic bug in your hook implementation that needs to be addressed.

Typical symptoms

  • Your application crashes with FST_ERR_HOOK_TIMEOUT when processing requests
  • Only certain requests trigger the error (those that go through the problematic hook)
  • The error message appears in logs with a timeout message
  • Requests to routes using the problematic hook fail or hang
  • The error occurs unpredictably or under high load

Common causes

  1. Your hook is performing a slow synchronous operation (database query, file I/O, CPU-intensive work) without awaiting it
  2. The hook contains an infinite loop or deadlock condition
  3. Your hook is making an external API call that takes too long or hangs
  4. The hook's timeout is set too low for the operation it performs
  5. A dependency used in the hook is blocking or slow
  6. The hook is waiting for a resource that never becomes available

How to fix "Error: FST_ERR_HOOK_TIMEOUT: Hook has exceeded the timeout limit"

1Identify which hook is timing out

Look at your error logs to see which hook lifecycle stage is failing:

javascript
fastify.addHook('onRequest', async (request, reply) => {
  // This is an 'onRequest' hook
});

fastify.addHook('preHandler', async (request, reply) => {
  // This is a 'preHandler' hook
});

Common hook types:
- onRequest: Very first hook, runs before validation
- preValidation: Before request validation
- preHandler: Before route handler executes
- onSend: After handler, before sending response
- onError: When an error occurs

Add logging to identify which hook is timing out:

javascript
fastify.addHook('onRequest', async (request, reply) => {
  console.log('onRequest hook starting');
  // your code
  console.log('onRequest hook completed');
});
2Check for synchronous blocking operations

Ensure your hook is not running synchronous blocking code that takes a long time:

javascript
// BAD: Synchronous file operations in a hook
fastify.addHook('preHandler', (request, reply, done) => {
  const data = fs.readFileSync('./large-file.txt', 'utf-8');
  done();
});

// GOOD: Use async file operations
fastify.addHook('preHandler', async (request, reply) => {
  const data = await fs.promises.readFile('./large-file.txt', 'utf-8');
});

Common blocking operations to avoid:
- fs.readFileSync() / fs.writeFileSync()
- require() for large modules
- Synchronous for loops over large datasets
- Synchronous encryption/hashing

3Check for infinite loops or missing conditions

Review your hook code for logic that might hang:

javascript
// BAD: Infinite loop possibility
fastify.addHook('preHandler', async (request, reply) => {
  while (true) { // Never exits!
    await someOperation();
  }
});

// BAD: Waiting for a condition that never happens
fastify.addHook('preHandler', async (request, reply) => {
  while (!request.user) {
    await new Promise(resolve => setTimeout(resolve, 100));
  }
});

// GOOD: Use timeouts with Promise.race()
fastify.addHook('preHandler', async (request, reply) => {
  const timeout = new Promise((_, reject) =>
    setTimeout(() => reject(new Error('Hook timeout')), 5000)
  );
  await Promise.race([yourAsyncOperation(), timeout]);
});
4Optimize slow database or API calls

If your hook makes database or API calls, ensure they complete quickly:

javascript
// BAD: No timeout on external call
fastify.addHook('preHandler', async (request, reply) => {
  const user = await db.query('SELECT * FROM users');
});

// GOOD: Add timeout and connection pooling
fastify.addHook('preHandler', async (request, reply) => {
  const controller = new AbortController();
  const timeout = setTimeout(() => controller.abort(), 3000); // 3s timeout
  
  try {
    const user = await fetch('https://api.example.com/user', {
      signal: controller.signal
    });
  } finally {
    clearTimeout(timeout);
  }
});

// For databases, ensure connection pooling is configured
const db = knex({
  client: 'pg',
  connection: {
    pool: { min: 2, max: 10 }
  }
});
5Increase hook timeout if operation is legitimately slow

If the operation is necessary and takes time, increase the hook timeout in Fastify options:

javascript
const fastify = require('fastify')({
  requestIdHeader: 'x-request-id',
  requestIdLogLabel: 'requestId',
  disableRequestLogging: false,
  requestTimeout: 30000, // 30 seconds for entire request
});

// For specific hooks, you can't directly configure timeout,
// but you can ensure your operations complete within Fastify's timeout
// Default request timeout is 30 seconds

Note: You cannot set per-hook timeouts in Fastify directly. The timeout applies to the entire request. If a hook is slow, you need to optimize it rather than just increase the timeout.

6Move long-running work outside the hook

If an operation is legitimately slow, move it outside the critical request path:

javascript
// BAD: Heavy processing in a hook blocks the request
fastify.addHook('preHandler', async (request, reply) => {
  request.userId = await expensiveUserVerification();
});

// GOOD: Cache the result or defer the work
const userCache = new Map();

fastify.addHook('preHandler', async (request, reply) => {
  const cached = userCache.get(request.headers.authorization);
  if (cached) {
    request.userId = cached;
    return;
  }
  request.userId = 'unknown';
});

// Verify user in background, update cache
setInterval(() => {
  updateUserCache();
}, 60000); // Every minute
7Add proper error handling to hooks

Ensure your hooks handle errors gracefully:

javascript
fastify.addHook('preHandler', async (request, reply) => {
  try {
    // your hook code
  } catch (error) {
    // Don't let unhandled errors cause timeouts
    fastify.log.error(error);
    reply.code(500).send({ error: 'Internal server error' });
  }
});

// Or throw and let Fastify's error handler deal with it
fastify.addHook('preHandler', async (request, reply) => {
  if (!request.user) {
    throw new Error('Unauthorized');
  }
});

fastify.setErrorHandler((error, request, reply) => {
  fastify.log.error(error);
  reply.code(500).send({ error: error.message });
});
8Test and monitor hook performance

Add timing instrumentation to measure hook performance:

javascript
fastify.addHook('preHandler', async (request, reply) => {
  const start = performance.now();
  
  try {
    // your hook code
  } finally {
    const duration = performance.now() - start;
    if (duration > 1000) { // Log if over 1 second
      fastify.log.warn({ duration }, 'Slow preHandler hook');
    }
  }
});

// Run your test suite with load testing
npm test

// Use tools like autocannon to load test
npx autocannon -c 10 -d 30 http://localhost:3000

Advanced notes

Hook execution order: Fastify hooks execute in a specific order: onRequest → preValidation → preHandler → onSend → onResponse. Each hook must complete before the next starts. A slow hook in an early stage (onRequest) will delay all subsequent processing.

Async vs callback syntax: Fastify hooks can use either async/await or callback (done) style. Async is preferred in modern code, but ensure you return a promise or call done():

javascript
// Async style
fastify.addHook('preHandler', async (request, reply) => {
  await operation();
});

// Callback style
fastify.addHook('preHandler', (request, reply, done) => {
  operation().then(() => done()).catch(done);
});

Default timeout: Fastify's default request timeout is 30 seconds (requestTimeout: 30000). All hooks must complete within this window combined.

Per-route hooks: You can also use per-route hooks which execute only for specific routes:

javascript
fastify.route({
  url: '/slow',
  method: 'GET',
  onRequest: [slowHook],
  handler: (request, reply) => {
    reply.send({ ok: true });
  }
});

Debugging: Enable verbose logging to see hook execution:

javascript
const fastify = require('fastify')({
  logger: {
    level: 'debug'
  }
});

This will show detailed timing information for hook and route execution.

Frequently asked questions

What does "FST_ERR_HOOK_TIMEOUT" mean?
Fastify enforces timeout limits on hooks to prevent them from hanging indefinitely and blocking request processing. ). When a hook exceeds its configured timeout threshold without completing, Fastify immediately terminates the hook execution and throws this error.
How do I fix "FST_ERR_HOOK_TIMEOUT"?
The FST_ERR_HOOK_TIMEOUT error occurs when a Fastify hook (onRequest, onSend, etc.) takes longer than the allowed timeout to complete. This error indicates that your hook is either performing long-running operations or is stuck in an infinite loop. Resolving this requires optimizing the hook code or adjusting timeout configuration.
What causes "FST_ERR_HOOK_TIMEOUT"?
Your hook is performing a slow synchronous operation (database query, file I/O, CPU-intensive work) without awaiting it The hook contains an infinite loop or deadlock condition Your hook is making an external API call that takes too long or hangs
Is the "FST_ERR_HOOK_TIMEOUT" error serious?
Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.

Official resources & further reading