different-ai/openwork · error · InterpreterRuntimeError

String.${method} expects a regular expression (a /pattern/fl

Error message

String.${method} expects a regular expression (a /pattern/flags literal or new RegExp(...)) or a string pattern, not ${arg === null ? "null" : typeof arg}.

What it means

CodeMode's sandboxed String regex methods (match, replace, split, search) accept only a /pattern/flags RegExp literal, a `new RegExp(...)` value, or a plain string pattern. This throw happens when the pattern argument is some other type (null, number, object, array, undefined). The library throws early so the host runtime never sees non-pattern data passed to its safe RegExp wrapper.

Source

Thrown at packages/codemode/src/stdlib/regexp.ts:33

export const regexFailureReason = (error: unknown): string =>
  (error instanceof Error ? error.message : String(error)).replace(/^Invalid regular expression:\s*/i, "")

export const escapeRegexHint =
  'To match special characters like ( ) [ ] { } + * ? . literally, escape them with a backslash (e.g. "\\\\(") or test for them with String.includes instead.'

export const toHostRegex = (arg: unknown, method: string, node: AstNode, extraFlags = ""): RegExp => {
  if (arg instanceof SandboxRegExp) return arg.regex
  if (typeof arg === "string") {
    try {
      return new RegExp(arg, extraFlags)
    } catch (error) {
      throw new InterpreterRuntimeError(
        `String.${method} received the string ${JSON.stringify(arg)}, which is not a valid regular expression pattern (${regexFailureReason(error)}). ${escapeRegexHint}`,
        node,
      ).as("SyntaxError")
    }
  }
  throw new InterpreterRuntimeError(
    `String.${method} expects a regular expression (a /pattern/flags literal or new RegExp(...)) or a string pattern, not ${arg === null ? "null" : typeof arg}.`,
    node,
  )
}

export const matchToValue = (match: RegExpMatchArray): Array<unknown> => {
  const result: Array<unknown> = Array.from(match, (group) => group)
  if (match.index !== undefined) (result as Record<string, unknown> & Array<unknown>).index = match.index
  if (match.groups) {
    const groups: SafeObject = Object.create(null) as SafeObject
    for (const [key, group] of Object.entries(match.groups)) {
      if (!isBlockedMember(key)) groups[key] = group
    }
    ;(result as Record<string, unknown> & Array<unknown>).groups = groups
  }
  return result
}

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Coerce the pattern to a string first: `"abc".match(String(pattern))`.
  2. Wrap dynamic patterns in `new RegExp(String(raw), flags)` before use.
  3. Fix the upstream value so it is a string or RegExp, not null/undefined/number.
  4. If the value may legitimately be absent, default it: `pattern ?? ""`.

Example fix

// before
const parts = csv.split(delimiter) // delimiter is null
// after
const parts = csv.split(new RegExp(String(delimiter ?? ",")))
Defensive patterns

Strategy: type-guard

Validate before calling

function isPattern(p) { return typeof p === "string" || p instanceof RegExp }
if (!isPattern(pattern)) throw new TypeError("pattern must be a string or RegExp")

Type guard

const isRegExpLike = (v) => typeof v === "string" || v instanceof RegExp

Try / catch

try { result = str.match(pattern) } catch (e) { if (String(e).includes("expects a regular expression")) result = null }

Prevention

When it happens

Trigger: Calling e.g. `"abc".match(123)`, `"abc".replace(null, "x")`, `"a,b".split([","])`, or passing an undefined variable as the pattern argument to any String regex method.

Common situations: Variables intended to hold a pattern end up null because an upstream lookup failed; JSON-decoded data yields numbers/objects where a pattern string was expected; developers forget to wrap a pattern in RegExp or quotes.

Related errors


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/0878a671ea4a2ba8. Report an issue: GitHub.