This error occurs when the URL constructor or URL-related functions receive an argument that is not a string or URL object, such as undefined, null, a number, or other invalid types.
This TypeError is thrown when Node.js URL APIs (like the WHATWG URL constructor, url.parse(), or other URL-related functions) receive an argument of an incorrect type. Node.js expects either a valid string containing a URL or an existing URL object instance. The error is part of Node.js's argument validation system, which immediately throws TypeErrors when function parameters don't match expected types. This prevents potentially dangerous operations from proceeding with invalid data. The URL constructor and related APIs are strict about type checking because parsing URLs requires string operations, and passing non-string values could lead to unexpected behavior or security vulnerabilities.
Check your stack trace to find the exact line where the URL constructor or url.parse() is called. Look for patterns like:
// Common problematic patterns
new URL(undefined);
new URL(process.env.MISSING_VAR);
new URL(someObject);
new URL(123);Add logging before the URL creation to inspect the value:
console.log('URL value:', typeof urlValue, urlValue);
new URL(urlValue);Validate that your URL argument is a string before passing it to the URL constructor:
// Check if the value is a valid string
if (typeof urlString !== 'string' || !urlString) {
throw new Error('Invalid URL: expected non-empty string');
}
const url = new URL(urlString);For optional URLs, provide fallback values:
const apiUrl = process.env.API_URL || 'https://api.example.com';
const url = new URL(apiUrl);If you're using environment variables, ensure they're properly loaded before URL construction:
// Load environment variables
require('dotenv').config();
// Validate required URLs exist
if (!process.env.DATABASE_URL) {
throw new Error('DATABASE_URL environment variable is required');
}
const dbUrl = new URL(process.env.DATABASE_URL);For Next.js applications, check that variables are prefixed correctly:
// Client-side variables need NEXT_PUBLIC_ prefix
const apiUrl = process.env.NEXT_PUBLIC_API_URL;
if (!apiUrl) {
throw new Error('NEXT_PUBLIC_API_URL is not defined');
}Wrap URL construction in error handling to provide better error messages:
function createURL(urlString) {
if (typeof urlString !== 'string') {
throw new TypeError(
`Expected string for URL, received ${typeof urlString}`
);
}
try {
return new URL(urlString);
} catch (error) {
throw new Error(
`Failed to create URL from: "${urlString}". ${error.message}`
);
}
}
// Usage
const url = createURL(process.env.API_URL);For optional URLs, return null or a default:
function safeCreateURL(urlString, defaultUrl = null) {
if (!urlString || typeof urlString !== 'string') {
return defaultUrl;
}
try {
return new URL(urlString);
} catch {
return defaultUrl;
}
}If you need to work with URL objects or other types, convert them appropriately:
// If you have a URL object, use it directly or convert to string
const existingUrl = new URL('https://example.com');
// Use the URL object directly (no need to convert)
fetch(existingUrl);
// Or explicitly convert to string when needed
const urlString = existingUrl.toString();
const newUrl = new URL(urlString);For numbers or other types that represent URLs:
// Convert port number to full URL string
const port = 3000;
const url = new URL(`http://localhost:${port}`);Type Validation Libraries: For larger applications, consider using runtime validation libraries like Zod or Joi to validate configuration and environment variables at startup:
import { z } from 'zod';
const envSchema = z.object({
DATABASE_URL: z.string().url(),
API_URL: z.string().url().optional(),
PORT: z.string().transform(Number)
});
const env = envSchema.parse(process.env);
const dbUrl = new URL(env.DATABASE_URL);URL vs. url.parse(): The WHATWG URL constructor (new URL()) is stricter than the legacy url.parse(). If you need more lenient parsing, url.parse() accepts non-string values but will return unexpected results. However, WHATWG URL is recommended for modern Node.js applications.
TypeScript Integration: Use TypeScript to catch type errors at compile time:
function buildApiUrl(endpoint: string): URL {
const baseUrl: string = process.env.API_URL!;
return new URL(endpoint, baseUrl);
}URL Constructor with Base URLs: Remember that the URL constructor accepts a second parameter for relative URLs. Ensure both parameters are strings:
// Both arguments must be strings
new URL('/api/users', 'https://example.com'); // ✓ Valid
new URL('/api/users', undefined); // ✗ Throws errorCommon Framework Patterns: In frameworks like Express or Fastify, configuration objects might require URL strings. Always validate configuration before passing to framework initialization to get clearer error messages at startup rather than during request 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