facebook/docusaurus · error · TypeError
Url must be a string. Received ${typeof component}
Error message
Url must be a string. Received ${typeof component} What it means
Thrown by normalizeUrl() inside the per-segment loop when an element of the input array is not a string. normalizeUrl is a URL-join utility that walks each segment assuming it is a string; a non-string element (number, undefined, null, object) is a type error in the caller. The error reports the typeof of the offending segment.
Source
Thrown at packages/docusaurus-utils/src/urlUtils.ts:57
if (first.startsWith('file:') && urls[0].startsWith('/')) {
// Force a double slash here, else we lose the information that the next
// segment is an absolute path
urls[0] = `${first}//${urls[0]}`;
} else {
urls[0] = first + urls[0];
}
}
// There must be two or three slashes in the file protocol,
// two slashes in anything else.
const replacement = urls[0].match(/^file:\/\/\//) ? '$1:///' : '$1://';
urls[0] = urls[0].replace(/^(?<protocol>[^/:]+):\/*/, replacement);
for (let i = 0; i < urls.length; i += 1) {
let component = urls[i];
if (typeof component !== 'string') {
throw new TypeError(`Url must be a string. Received ${typeof component}`);
}
if (component === '') {
if (i === urls.length - 1 && hasEndingSlash) {
resultArray.push('/');
}
continue;
}
if (component !== '/') {
if (i > 0) {
// Removing the starting slashes for each component but the first.
component = component.replace(
/^\/+/,
// Special case where the first element of rawUrls is empty
// ["", "/hello"] => /hello
component.startsWith('/') && !hasStartingSlash ? '/' : '',
);View on GitHub (pinned to 3f483e80e3)
Solutions
- Inspect the error's typeof hint and trace which segment of the input array matches that type.
- Coerce or default every segment to a string before calling normalizeUrl (e.g. `segment ?? ''` or String(segment)).
- Filter out non-string segments upstream with arr.filter((s): s is string => typeof s === 'string') if empty/missing segments should be dropped.
- Add a runtime assertion at the boundary where the array is assembled so the bug surfaces at its source.
Example fix
// before normalizeUrl([baseUrl, maybeUndefinedVersion, slug]); // after normalizeUrl([baseUrl, version ?? '', slug].filter(Boolean));
Defensive patterns
Strategy: type-guard
Validate before calling
function allStrings(segments: unknown[]): segments is string[] {
return segments.every(s => typeof s === 'string');
}
if (!allStrings(rawUrls)) {
rawUrls = rawUrls.filter((s): s is string => typeof s === 'string');
}
normalizeUrl(rawUrls); Type guard
function isStringArray(arr: unknown): arr is string[] {
return Array.isArray(arr) && arr.every(s => typeof s === 'string');
} Try / catch
try {
normalizeUrl(rawUrls);
} catch (err) {
if (err instanceof TypeError && err.message.startsWith('Url must be a string')) {
// a non-string segment slipped in; filter and retry
}
throw err;
} Prevention
- Type the segments array as string[] at every boundary so non-strings are caught at compile time.
- Filter or default optional segments (version ?? '') before assembling the array.
- Validate config-sourced URL pieces with a typeof check before passing them to normalizeUrl.
When it happens
Trigger: Calling normalizeUrl([...segments]) where at least one segment is not a string — e.g. a variable that evaluated to undefined, a number accidentally included, or an object produced by a buggy expression. The check is reached for every segment after the protocol-normalization step, so even segments beyond the first are type-checked.
Common situations: Building a URL from config values where one optional field was undefined. Spread of an array that contains nulls. A locale or version variable that is a number rather than a string. Calling normalizeUrl on a value that came from JSON where the field was absent.
Related errors
- Invalid module path of type "name=${typeof modulePath}" with
- Can't parse URL ${str}${base ? ` with base ${base}` : ''}
- Invalid command: ${command}
- Invalid package manager choice ${packageManager}. Must be on
- Directory already exists at path=${dest}!
AI-assisted analysis of facebook/docusaurus@3f483e80e3 (2026-08-12).
Data as JSON: /api/errors/4c74be91ff5efc3b.
Report an issue: GitHub.