This error occurs in Fastify when you try to register a decorator (plugin, hook, or utility method) with a name that already exists. Fastify prevents duplicate decorator registration to avoid silent overwrites. The fix involves checking for existing decorators, using unique names, or explicitly overwriting when intentional.
Fastify decorators are custom methods, utilities, or properties you add to the Fastify instance, request, or reply objects to extend their functionality. When you attempt to register a decorator with a name that already exists on the target object, Fastify throws this error to prevent accidental data loss or unpredictable behavior from silent overwrites. This is a safety feature: silently replacing an existing decorator could cause bugs that are difficult to debug, especially in large applications with multiple plugins. The error forces you to be explicit about your intentions.
The error message includes the name of the conflicting decorator:
Error: FST_ERR_DEC_ALREADY_PRESENT: Fastify instance already has 'myDecorator' decoratorNote the decorator name (in this example, 'myDecorator'). This tells you exactly what is being duplicated. Check the full error stack trace to see where the duplicate registration is happening.
Search your codebase for where this decorator is being registered:
# Search for fastify.decorate calls
grep -r "fastify.decorate.*myDecorator" .
grep -r "fastify.decorateRequest.*myDecorator" .
grep -r "fastify.decorateReply.*myDecorator" .
# Also search in plugins
grep -r "instance.decorate.*myDecorator" .Replace 'myDecorator' with your actual decorator name. Make a list of all locations where this decorator is being registered.
If you are using plugins, verify that each plugin is registered only once:
// WRONG: plugin registered twice
await fastify.register(myPlugin);
await fastify.register(myPlugin); // Duplicate!
// CORRECT: plugin registered once
await fastify.register(myPlugin);Also check your plugin loading code:
// Bad: loading all files may include duplicates
const files = readdirSync('./plugins');
for (const file of files) {
await fastify.register(require(`./plugins/${file}`));
}
// If './plugins' contains both 'my-plugin.js' and 'my-plugin/index.js',
// it will be registered twice!Verify that when you import and register plugins, you are not loading them multiple ways:
// WRONG: loading same plugin via different paths
const plugin1 = require('./plugin');
const plugin2 = require('./plugin.js');
await fastify.register(plugin1);
await fastify.register(plugin2); // Same plugin, different require path!
// CORRECT: use absolute or consistent relative paths
const plugin = require(path.resolve(__dirname, 'plugin.js'));
await fastify.register(plugin); // Only onceIf you are intentionally creating multiple similar decorators, give them unique names:
// WRONG: Same name registered multiple times
fastify.decorate('utils', utilsV1);
fastify.decorate('utils', utilsV2); // Conflict!
// CORRECT: Use unique names
fastify.decorate('utils', utilsV1);
fastify.decorate('utilsV2', utilsV2);
// Or namespace them
fastify.decorate('utils', { v1: utilsV1, v2: utilsV2 });Use hasDecorator to check if a decorator already exists:
// Check instance decorators
if (!fastify.hasDecorator('myDecorator')) {
fastify.decorate('myDecorator', myDecoratorFunction);
}
// Check request decorators
if (!fastify.hasRequestDecorator('userId')) {
fastify.decorateRequest('userId', null);
}
// Check reply decorators
if (!fastify.hasReplyDecorator('sendCustom')) {
fastify.decorateReply('sendCustom', function() { /* ... */ });
}This allows safe idempotent registration, useful in testing or dynamic scenarios.
If you genuinely want to replace an existing decorator (e.g., mocking in tests), use the decorate methods with the override option:
// Override an existing decorator
fastify.decorate('myDecorator', newImplementation, true);
// Third parameter true allows overriding
fastify.decorateRequest('userId', newValue, true);
fastify.decorateReply('sendCustom', newFunction, true);Be cautious with this approach - only override when you're certain about the implications.
If the conflict is between two plugins, check their code:
// In plugin-a.js
module.exports = async (fastify) => {
fastify.decorate('db', dbInstance);
};
// In plugin-b.js
module.exports = async (fastify) => {
fastify.decorate('db', anotherDbInstance); // Conflict!
};Solutions:
1. Only load one of the conflicting plugins
2. Ask the plugin maintainers to use different names
3. Fork and modify one plugin to use a different name
4. Use decorator scope (decorate different parts: fastify, request, reply) if both are needed
After fixing the duplicate registration, start your application to verify the error is gone:
# Start the application
node index.js
# Or with npm
npm startThe application should start without the FST_ERR_DEC_ALREADY_PRESENT error. If you're using tests:
npm testEnsure all tests pass and the decorator is available where expected.
Decorator scopes: Fastify has three different decorator scopes. They are independent, so you can have the same name in different scopes:
fastify.decorate('data', 'instance-level'); // On fastify instance
fastify.decorateRequest('data', 'request-level'); // On request object
fastify.decorateReply('data', 'reply-level'); // On reply object
// Each scope maintains separate decorators, so no conflictPlugin scoping: If a plugin should only decorate instances of itself (not the parent fastify instance), use plugin scoping:
module.exports = async (fastify, options) => {
// This decoration is scoped to this plugin's context
fastify.decorate('pluginSpecificHelper', helperFunction);
};Fastify versioning: Different Fastify versions may have different behavior around decorators. Always ensure your plugins are compatible with your Fastify version. Check the plugin's peerDependencies in package.json.
Testing tip: When testing Fastify applications with decorators, be aware that the test fastify instance is separate from your application instance. Decorators added in one test don't carry over to another unless you're reusing the same instance.
Performance consideration: Decorators are looked up by name on every access, so naming them clearly and avoiding excessive numbers of decorators is a best practice for maintainability, not performance.
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