babel/babel · error · Error

${msg(loc)} must be a undefined, a boolean, a string/Functio

Error message

${msg(loc)} must be a undefined, a boolean, a string/Function/RegExp or an array of those, got ${JSON.stringify(value as any)}

What it means

Thrown by assertBabelrcSearch when 'babelrcRoots' is a single non-array value that is not undefined, boolean, string, Function, or RegExp. The offending value is JSON.stringified in the message.

Source

Thrown at packages/babel-core/src/config/validation/option-assertions.ts:326

export function assertBabelrcSearch(
  loc: OptionPath,
  value: unknown,
): BabelrcSearch | undefined {
  if (value === undefined || typeof value === "boolean") {
    return value;
  }

  if (Array.isArray(value)) {
    value.forEach((item, i) => {
      if (!checkValidTest(item)) {
        throw new Error(
          `${msg(access(loc, i))} must be a string/Function/RegExp.`,
        );
      }
    });
  } else if (!checkValidTest(value)) {
    throw new Error(
      `${msg(loc)} must be a undefined, a boolean, a string/Function/RegExp ` +
        `or an array of those, got ${JSON.stringify(value as any)}`,
    );
  }
  return value as BabelrcSearch;
}

export function assertPluginList(
  loc: OptionPath,
  value: unknown[] | null | undefined,
): PluginItem[] {
  const arr = assertArray(loc, value);
  if (arr) {
    // Loop instead of using `.map` in order to preserve object identity
    // for plugin array for use during config chain processing.
    arr.forEach((item, i) => assertPluginItem(access(loc, i), item));
  }
  return arr as PluginItem[];

View on GitHub (pinned to 06b6eae39d)

Solutions

  1. Pass true to enable all roots, false to disable, or a glob string/array of globs.
  2. Convert object wrappers to a flat array of path strings.
  3. Omit to use the default (babelrc disabled outside the root).

Example fix

// before
{ babelrcRoots: { roots: ['packages/*'] } }
// after
{ babelrcRoots: ['packages/*'] }
Defensive patterns

Strategy: type-guard

Validate before calling

function isBabelrcSearch(v) {
  if (v === undefined || typeof v === 'boolean') return true;
  if (typeof v === 'string' || typeof v === 'function' || v instanceof RegExp) return true;
  if (Array.isArray(v)) return v.every(isBabelrcSearch);
  return false;
}
if (!isBabelrcSearch(opts.babelrcRoots)) {
  throw new Error('babelrcRoots invalid');
}

Type guard

function isBabelrcSearch(v: unknown): boolean {
  if (v === undefined || typeof v === 'boolean') return true;
  if (typeof v === 'string' || typeof v === 'function' || v instanceof RegExp) return true;
  if (Array.isArray(v)) return v.every(isBabelrcSearch);
  return false;
}

Try / catch

try {
  babel.loadOptions(opts);
} catch (e) {
  if (e instanceof Error && /babelrcRoots must be/.test(e.message)) {
    opts.babelrcRoots = true;
    return babel.loadOptions(opts);
  }
  throw e;
}

Prevention

When it happens

Trigger: babelrcRoots: { roots: ['a'] } (object); babelrcRoots: 42; babelrcRoots: null. The loc points at the option itself.

Common situations: Passing a config object expecting it to be merged; using a number expecting boolean semantics; legacy configs migrated from .babelrcrc roots.

Related errors


AI-assisted analysis of babel/babel@06b6eae39d (2026-08-03). Data as JSON: /data/errors/d00944bf685ca44c.json. Report an issue: GitHub.