facebook/docusaurus · error

Invalid module path of type "name=${typeof modulePath}" with

Error message

Invalid module path of type "name=${typeof modulePath}" with value "name=${modulePath}"

What it means

Thrown by loadFreshModule() as a type guard before attempting to load anything: if modulePath is not a string, the function refuses to proceed. This guards jiti.import (which expects a string) from being called with a number, object, undefined, or null that would otherwise surface as an opaque internal error.

Source

Thrown at packages/docusaurus-utils/src/moduleUtils.ts:33

  fsCache: true,
  // Bypass Node.js runtime require cache for hot reloads
  moduleCache: false,

  interopDefault: true,
  debug: DEBUG,
});

/*
jiti is able to load ESM, CJS, JSON, TS modules
 */
export async function loadFreshModule(
  modulePath: string,
  options?: {
    default?: true; // Use this when only the default export matters
  },
): Promise<unknown> {
  if (typeof modulePath !== 'string') {
    throw new Error(
      logger.interpolate`Invalid module path of type "name=${typeof modulePath}" with value "name=${modulePath}"`,
    );
  }
  try {
    const module = await jiti.import(modulePath, {
      default: options?.default,
    });

    if (DEBUG) {
      console.log('Jiti module loaded', {
        modulePath,
        options,
        type: typeof module,
        keys:
          module && typeof module === 'object'
            ? Object.keys(module)
            : undefined,
        module,

View on GitHub (pinned to 3f483e80e3)

Solutions

  1. Inspect the error's interpolated value (and typeof) to see what non-string was passed.
  2. Trace the call site backward to find where modulePath was sourced and ensure that variable is a string path before calling loadFreshModule.
  3. Add a default or guard at the source so the path is never undefined — e.g. read from config with a fallback.
  4. If the path comes from user config, validate it with typeof check and emit a clearer user-facing error before reaching loadFreshModule.

Example fix

// before
const presetPath = config.presets[0].path; // undefined if misconfigured
await loadFreshModule(presetPath);

// after
if (typeof presetPath !== 'string') {
  throw new Error('presets[0].path must be a string module path');
}
await loadFreshModule(presetPath);
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof modulePath !== 'string' || modulePath.length === 0) {
  throw new Error(`Module path must be a non-empty string, got ${typeof modulePath}: ${modulePath}`);
}
await loadFreshModule(modulePath, options);

Type guard

function isNonEmptyString(v: unknown): v is string {
  return typeof v === 'string' && v.length > 0;
}

Try / catch

try {
  await loadFreshModule(modulePath, options);
} catch (err) {
  if (err instanceof Error && err.message.startsWith('Invalid module path')) {
    // the caller passed a non-string; fix the source of modulePath
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling loadFreshModule with a non-string value — typically because a config lookup returned undefined (e.g. a plugin path option was not set and the variable is undefined), or a number was passed where a path string was expected. The interpolated message reports both the typeof and the coerced value to aid debugging.

Common situations: A docusaurus.config.js or plugin config value is undefined at the point it is passed to loadFreshModule (e.g. a presets entry that is missing its path). Destructuring a config object and passing the wrong field. A programmatic caller that loaded a path from JSON where the field was numeric or absent.

Related errors


AI-assisted analysis of facebook/docusaurus@3f483e80e3 (2026-08-12). Data as JSON: /api/errors/0619582687ae28b3. Report an issue: GitHub.