This error occurs when you attempt to register the same Fastify plugin multiple times, either directly in your code or through a chain of dependencies. Fastify prevents duplicate plugin registration to avoid conflicts, state duplication, and unpredictable behavior.
Fastify maintains an internal registry of all loaded plugins to ensure each plugin is initialized exactly once per Fastify instance. When you try to register a plugin that Fastify has already loaded, it throws this error to prevent duplicate initialization, which could cause: - State conflicts (plugins maintaining internal state would have duplicate instances) - Memory leaks (resources allocated by the first plugin instance not being cleaned up) - Unexpected behavior (hooks, routes, or decorators being registered twice) - Race conditions (plugins modifying shared state simultaneously) This is a safety mechanism, not a sign of the plugin itself being broken. The issue is in how the application is loading the plugin.
The error message should include the plugin name. Look at your Fastify initialization code to find where you register plugins:
const fastify = require('fastify')();
// The error will mention which of these plugins is registered twice
fastify.register(require('@fastify/cors'));
fastify.register(require('@fastify/jwt'));
fastify.register(require('./my-custom-plugin'));If the error message is vague, add logging to see the exact sequence of plugin registrations:
fastify.addHook('onRegister', (instance, opts) => {
console.log('Plugin registered:', opts);
});Search for the problematic plugin name across your project to find all registration points:
# Search for plugin registration
grep -r "@fastify/cors" src/
grep -r "register(" src/Each plugin should be registered exactly once. Example of what to avoid:
// ❌ Wrong - plugin registered twice
fastify.register(require('@fastify/cors'));
// ... more code ...
fastify.register(require('@fastify/cors')); // Duplicate!
// ✅ Correct - plugin registered once
fastify.register(require('@fastify/cors'));Sometimes the same plugin is registered through different module imports:
// app.js
const plugin = require('./my-plugin');
fastify.register(plugin);
// routes/api.js - imported by app.js
const plugin = require('./my-plugin');
fastify.register(plugin); // Same plugin, different import!Move plugin registration to a single location and pass the fastify instance where needed:
// app.js - single registration
const plugin = require('./my-plugin');
fastify.register(plugin);
// routes/api.js - no plugin registration
module.exports = async (fastify) => {
// Use plugin features without re-registering
fastify.myDecorator(); // Plugin already loaded
};If the error appears after updating dependencies, it may be a transitive dependency issue. Check your package.json and dependency tree:
# List all versions of a package in your dependency tree
npm list @fastify/cors
# Look for duplicates - should show only one versionIf you see multiple versions, pin to a single version in package.json:
{
"dependencies": {
"@fastify/cors": "^8.0.0",
"some-package": "^1.0.0"
}
}Then reinstall:
rm -rf node_modules package-lock.json
npm installIf this error occurs during testing, ensure you properly close the Fastify instance between tests:
// ❌ Wrong - fastify instance reused
let fastify;
beforeAll(() => {
fastify = require('fastify')();
fastify.register(require('@fastify/cors'));
});
afterEach(() => {
// Not closing fastify!
});
test('test 1', () => {
// fastify still has the plugin from test setup
});Instead, create a fresh instance per test:
// ✅ Correct - fresh instance per test
beforeEach(async () => {
fastify = require('fastify')();
fastify.register(require('@fastify/cors'));
await fastify.ready();
});
afterEach(async () => {
await fastify.close();
});If you're registering plugins in nested route contexts, use the prefix option to isolate them:
// Register plugin once at root level
fastify.register(async (instance) => {
// All sub-routes inherit this plugin
instance.decorateRequest('user', null);
});
// Bad - trying to re-register in a sub-route
fastify.register(async (instance) => {
instance.register(require('@fastify/cors')); // OK here
instance.register(async (subInstance) => {
// Don't re-register parent plugins here
});
});
// Good - use existing decorators in nested routes
fastify.register(async (parentInstance) => {
parentInstance.register(require('@fastify/cors'));
parentInstance.register(async (subInstance) => {
// Decorators from parent are inherited
subInstance.get('/', (req, res) => {
// Can use req.user from parent plugin
});
});
});Plugin namespacing: Fastify uses the plugin function's name (or a custom namespace) to track registered plugins. If you're dynamically loading plugins, ensure unique identifiers:
const plugin = require('./my-plugin');
// Plugin will be tracked by its function.name property
fastify.register(plugin);
// If you want explicit control, pass a name in options:
fastify.register(plugin, { name: 'my-custom-name' });Fastify context and scope: Each Fastify instance maintains its own plugin registry. If you're creating multiple Fastify instances, you can register the same plugin to each instance separately:
const fastify1 = require('fastify')();
const fastify2 = require('fastify')();
// Same plugin, different instances - no conflict
fastify1.register(require('@fastify/cors'));
fastify2.register(require('@fastify/cors'));Plugin composition patterns: Modern Fastify applications often use composition patterns. Make sure you understand whether a helper function wraps plugin registration or is the plugin itself:
// This is a plugin factory - returns a plugin function
const createMyPlugin = (options) => {
return async (fastify) => {
// Actual plugin code
};
};
// Register once, pass options if needed
fastify.register(createMyPlugin({ mode: 'strict' }));Error stack trace analysis: The error stack trace will usually point to the exact line where the duplicate registration happened. Use --trace-warnings flag for more details:
node --trace-warnings app.jsThis helps identify whether the duplicate comes from your code or a dependency.
Error: EMFILE: too many open files, watch
EMFILE: fs.watch() limit exceeded
Error: Middleware next() called multiple times (next() invoked twice)
Express middleware next() called multiple times
Error: Worker failed to initialize (worker startup error)
Worker failed to initialize in Node.js
Error: EMFILE: too many open files, open 'file.txt'
EMFILE: too many open files
Error: cluster.fork() failed (cannot create child process)
cluster.fork() failed - Cannot create child process