This TypeError occurs when path.relative() is called with non-string arguments, such as undefined, null, numbers, or objects. Both the from and to parameters must be valid string values representing file paths.
This error is thrown by Node.js when you call the path.relative() method without providing two string arguments. The path.relative() method calculates the relative path from one directory to another, but it requires both the source (from) and destination (to) paths to be strings. The error typically occurs when variables passed to path.relative() are undefined, null, or of the wrong type (like numbers, objects, or Buffers). This often happens when path variables are not properly initialized, when function parameters are missing, or when environment variables or configuration values fail to load correctly. Node.js enforces strict type checking for path module methods to prevent unexpected behavior and ensure path operations work correctly across different operating systems.
Examine the stack trace to find the exact location where the error occurs:
// Example error stack trace
TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received undefined
at new NodeError (node:internal/errors:372:5)
at validateString (node:internal/validators:124:11)
at Object.relative (node:internal/path:1171:5)Look for the file and line number in your code that called path.relative().
Before calling path.relative(), log the values to see what's being passed:
const path = require('path');
function getRelativePath(fromPath, toPath) {
console.log('fromPath:', fromPath, 'type:', typeof fromPath);
console.log('toPath:', toPath, 'type:', typeof toPath);
return path.relative(fromPath, toPath);
}This will reveal if either argument is undefined, null, or the wrong type.
Validate that both arguments are strings before using path.relative():
const path = require('path');
function getRelativePath(fromPath, toPath) {
if (typeof fromPath !== 'string' || typeof toPath !== 'string') {
throw new Error(`Invalid path arguments: from=${fromPath}, to=${toPath}`);
}
return path.relative(fromPath, toPath);
}This provides a clearer error message about which argument is invalid.
If path values might be undefined, provide fallback values:
const path = require('path');
function getRelativePath(fromPath, toPath) {
// Use current working directory as fallback
const from = fromPath || process.cwd();
const to = toPath || process.cwd();
return path.relative(from, to);
}Or use the nullish coalescing operator:
const relativePath = path.relative(
fromPath ?? process.cwd(),
toPath ?? process.cwd()
);If paths come from environment variables or config files, ensure they're loaded correctly:
const path = require('path');
// Check environment variable
const baseDir = process.env.BASE_DIR;
if (!baseDir) {
throw new Error('BASE_DIR environment variable is not set');
}
const targetDir = process.env.TARGET_DIR;
if (!targetDir) {
throw new Error('TARGET_DIR environment variable is not set');
}
const relativePath = path.relative(baseDir, targetDir);For configuration objects:
const config = require('./config.json');
if (!config.sourcePath || typeof config.sourcePath !== 'string') {
throw new Error('Invalid or missing sourcePath in config');
}
if (!config.destPath || typeof config.destPath !== 'string') {
throw new Error('Invalid or missing destPath in config');
}
const relativePath = path.relative(config.sourcePath, config.destPath);Use default parameters to ensure string values are always provided:
const path = require('path');
function calculateRelativePath(
fromPath = process.cwd(),
toPath = process.cwd()
) {
// Validate they're still strings (in case null was explicitly passed)
if (typeof fromPath !== 'string') {
throw new TypeError('fromPath must be a string');
}
if (typeof toPath !== 'string') {
throw new TypeError('toPath must be a string');
}
return path.relative(fromPath, toPath);
}Build a wrapper that handles validation and provides better error messages:
const path = require('path');
/**
* Safely calculate relative path between two directories
* @param {string} from - Source directory path
* @param {string} to - Destination directory path
* @returns {string} Relative path from 'from' to 'to'
* @throws {TypeError} If arguments are not strings
*/
function safeRelativePath(from, to) {
if (typeof from !== 'string') {
throw new TypeError(
`First argument 'from' must be a string, received ${typeof from}`
);
}
if (typeof to !== 'string') {
throw new TypeError(
`Second argument 'to' must be a string, received ${typeof to}`
);
}
if (from.length === 0) {
throw new Error('First argument cannot be an empty string');
}
if (to.length === 0) {
throw new Error('Second argument cannot be an empty string');
}
return path.relative(from, to);
}
// Usage
try {
const result = safeRelativePath('/src', '/dist');
console.log(result);
} catch (error) {
console.error('Path calculation failed:', error.message);
}TypeScript type safety: If you're using TypeScript, you can prevent this error at compile time by using strict null checks and proper type definitions. The @types/node package provides accurate types for the path module.
Path module vs fs.promises: When working with async file operations using fs.promises, ensure that path resolution happens after async operations complete, not before values are available.
Zero-length strings: Note that path.relative() treats zero-length strings specially - it uses the current working directory (process.cwd()) as a replacement. This can lead to unexpected results if you're not aware of this behavior.
Cross-platform considerations: While this error is about argument types, remember that path.relative() uses platform-specific path separators. Use path.posix.relative() or path.win32.relative() explicitly if you need consistent behavior across platforms.
Build tool integration: When integrating with build tools like webpack, rollup, or esbuild, ensure that plugin configurations provide valid path strings. Some tools may pass undefined during certain phases of the build process.
Error code evolution: In older versions of Node.js, this error might have been a generic TypeError without the ERR_INVALID_ARG_TYPE code. Modern Node.js versions (12+) use structured error codes for better error handling.
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