This error occurs when you try to access a property or function from a module that was not properly exported, or when module.exports is assigned inside a callback. It commonly happens when mixing CommonJS and ES Module syntax or importing non-existent named exports.
The "module.exports is undefined" error indicates that Node.js cannot find the exported value you're trying to import. In CommonJS modules, everything you want to expose must be explicitly assigned to module.exports or exports. When you require() a module, you receive whatever value was assigned to module.exports. If that assignment never happens, happens inside a callback, or if you try to destructure a named export that doesn't exist, you'll get undefined. This error is particularly common when developers try to use ES6 destructuring syntax (const { myFunction } = require('./module')) on a module that exports a single value or doesn't export the named property at all. It also occurs when reassigning module.exports after setting individual properties, which overwrites the original exports object.
Ensure module.exports assignments happen immediately, not inside callbacks or async functions:
// Wrong - exports assigned in callback
const fs = require('fs');
fs.readFile('config.json', (err, data) => {
module.exports = JSON.parse(data); // Too late!
});
// Correct - exports assigned immediately
const config = require('./config-loader');
module.exports = config;If you need to export async values, export the promise or use a factory function that returns a promise:
// Export a function that returns a promise
module.exports = async function loadConfig() {
const data = await fs.promises.readFile('config.json');
return JSON.parse(data);
};Verify that the module exports what you're trying to import. In the exporting file:
// module.js
function myFunction() { return 'hello'; }
function anotherFunction() { return 'world'; }
// Export both functions
module.exports = { myFunction, anotherFunction };Then import with matching names:
// main.js
const { myFunction, anotherFunction } = require('./module');
console.log(myFunction()); // 'hello'If the module exports a single value, don't use destructuring:
// Wrong - trying to destructure single export
const { myFunction } = require('./module'); // undefined!
// Correct - import the whole export
const myFunction = require('./module');Once you set properties on module.exports, avoid reassigning the entire object:
// Wrong - reassignment loses previous properties
module.exports.foo = 'bar';
module.exports.baz = 'qux';
module.exports = { newValue: 'test' }; // foo and baz are now gone!
// Correct - set all properties at once
module.exports = {
foo: 'bar',
baz: 'qux',
newValue: 'test'
};
// Or add properties without reassignment
exports.foo = 'bar';
exports.baz = 'qux';
exports.newValue = 'test';Remember: exports is a reference to module.exports. Reassigning exports itself breaks this reference, so always use module.exports for full reassignments.
Check your package.json to see which module system you're using:
{
"type": "module" // ES Modules
}If "type": "module" is present, use ES Module syntax throughout:
// ES Module syntax
export const myFunction = () => 'hello';
export default myFunction;
// Import
import myFunction, { myFunction as named } from './module.js';Without "type": "module" (CommonJS), use require/module.exports:
// CommonJS syntax
module.exports = { myFunction };
// Import
const { myFunction } = require('./module');Mixing these syntaxes causes compatibility issues and undefined exports.
If modules were previously loaded with incorrect exports, Node.js may have cached the old version. Clear the cache by restarting your application or manually clearing it:
// Clear cache for a specific module (development only)
delete require.cache[require.resolve('./module')];
// Then require again
const myModule = require('./module');In development, tools like nodemon automatically restart Node.js when files change, which clears the cache. For production, simply restart the Node.js process.
If using a transpiler (TypeScript, Babel), ensure you rebuild before testing:
npm run build
node dist/index.jsCircular dependencies: When module A requires module B, and module B requires module A, one of them will receive an incomplete exports object. To diagnose, add console.log statements in both modules to see the load order. Refactor to remove the circular dependency by extracting shared code into a third module.
Using `this` in exports: When exporting object methods that reference this, the context may not be what you expect. Arrow functions inherit this from the enclosing scope, while regular functions have their own this. Explicitly bind methods or use regular functions assigned to module.exports.
TypeScript interop: When importing CommonJS modules in TypeScript with esModuleInterop: true, you can use import module from 'module' syntax. Without this flag, use import * as module from 'module'. Ensure your tsconfig.json module settings match your runtime environment.
Webpack and bundlers: Module bundlers transform require() calls during build time. If exports are conditionally assigned or computed at runtime, the bundler may not capture them correctly. Use static exports whenever possible.
Default exports in CommonJS: When a CommonJS module uses module.exports = value (single value), importing it with ES Module syntax may require accessing .default: import mod from './module'; const value = mod.default; depending on your transpiler configuration.
Error: Listener already called (once event already fired)
EventEmitter listener already called with once()
Error: EACCES: permission denied, open '/root/file.txt'
EACCES: permission denied
Error: Invalid encoding specified (stream encoding not supported)
How to fix Invalid encoding error in Node.js readable streams
Error: EINVAL: invalid argument, open
EINVAL: invalid argument, open
TypeError: readableLength must be a positive integer (stream config)
TypeError: readableLength must be a positive integer in Node.js streams