facebook/flow · error

flow-remove-types: includes and excludes must be RegExp or…

Error message

flow-remove-types: includes and excludes must be RegExp or path strings. Got: ${pattern}

What it means

Thrown by flow-remove-types/register's `regexpPattern` helper while deciding whether a file should be transformed. The `includes`/`include` and `excludes`/`exclude` options accept only a string (treated as a very simplified glob: `.` is escaped and `*` becomes `.*`, optionally prefixed with `/`) or a RegExp-like object exposing a `.test` function. Anything else - arrays, numbers, booleans, plain objects - hits the final throw.

Solutions

  1. Pass a single string glob (e.g. `'src/*.js'`) or a single RegExp (e.g. `/\/src\/.*\.js$/`).
  2. If you have an array of globs, combine them into one RegExp: `new RegExp(globs.map(g => g.replace(/\./g,'\\.').replace(/\*/g,'.*')).join('|'))`.
  3. Do not use `?` or character classes in string globs - only `*` is expanded; switch to RegExp for anything richer.
  4. Remember `excludes` defaults to /\/node_modules\//; pass `excludes: null` to transform node_modules too.

Example fix

// before
require('flow-remove-types/register')({
  includes: ['src/**/*.js', 'lib/*.js'],
});

// after
require('flow-remove-types/register')({
  includes: /(\/src\/|\/lib\/).*\.js$/,
});
Defensive patterns

Strategy: validation

Validate before calling

function isValidPattern(p) {
  return p == null || typeof p === 'string' || p instanceof RegExp;
}

function normalizePatterns(globs) {
  // combine array-of-globs into the single RegExp the register hook accepts
  if (Array.isArray(globs)) {
    return new RegExp(globs.map(g =>
      '/' + g.replace(/\./g, '\\.').replace(/\*/g, '.*')
    ).join('|'));
  }
  return globs;
}

if (!isValidPattern(opts.includes) || !isValidPattern(opts.excludes)) {
  throw new TypeError('includes/excludes must be a string glob or RegExp');
}

Prevention

When it happens

Trigger: Calling `require('flow-remove-types/register')({includes: ['src/**/*.js']})` (an array, as used by babel/jest configs), `{excludes: true}`, or `{includes: {test: 'src'}}`. The error surfaces lazily on the first `require()` of a .js/.jsx/.mjs/.cjs/.flow/.es6 file because that is when the pirates hook matcher runs.

Common situations: Copy-pasting an array-of-globs config from babel-plugin or jest transform settings; passing a minimatch pattern expecting full glob semantics (`?`, `**` special-casing); passing `excludes: undefined` vs `excludes: null` confusion (null is fine - it disables the default /node_modules/ exclusion).

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of facebook/flow@f88ac94bcf (2026-08-20). Data as JSON: /api/errors/80935009ba403946. Report an issue: GitHub.

Appendix: source

Thrown at packages/flow-remove-types/register.js:73

// Given a null | string | RegExp | any, returns null | Regexp or throws a
// more helpful error.
function regexpPattern(pattern) {
  if (!pattern) {
    return pattern;
  }
  // A very simplified glob transform which allows passing legible strings like
  // "myPath/*.js" instead of a harder to read RegExp like /\/myPath\/.*\.js/.
  if (typeof pattern === 'string') {
    pattern = pattern.replace(/\./g, '\\.').replace(/\*/g, '.*');
    if (pattern[0] !== '/') {
      pattern = '/' + pattern;
    }
    return new RegExp(pattern);
  }
  if (typeof pattern.test === 'function') {
    return pattern;
  }
  throw new Error(
    'flow-remove-types: ' +
      'includes and excludes must be RegExp or path strings. Got: ' +
      pattern,
  );
}

View on GitHub (pinned to f88ac94bcf)