different-ai/openwork · error · InterpreterRuntimeError

String.replaceAll requires a regular expression with the glo

Error message

String.replaceAll requires a regular expression with the global (g) flag: write /${pattern.source}/${pattern.flags}g, or use String.replace to replace only the first match.

What it means

In this sandbox String.replaceAll with a RegExp pattern requires the global (g) flag, mirroring the host JavaScript spec where replaceAll with a non-global regex throws a TypeError. The library throws proactively with an actionable message that prints the corrected regex literal (source + flags + g) and points to String.replace for first-match-only replacement.

Source

Thrown at packages/codemode/src/interpreter/runtime.ts:426

    case "startsWith":
      result = value.startsWith(str(0), optNum(1))
      break
    case "endsWith":
      result = value.endsWith(str(0), optNum(1))
      break
    case "indexOf":
      result = value.indexOf(str(0), optNum(1))
      break
    case "lastIndexOf":
      result = value.lastIndexOf(str(0), optNum(1))
      break
    case "replace":
    case "replaceAll": {
      if (args[0] instanceof SandboxRegExp) {
        const pattern = (args[0] as SandboxRegExp).regex
        const replacement = str(1)
        if (name === "replaceAll" && !pattern.global) {
          throw new InterpreterRuntimeError(
            `String.replaceAll requires a regular expression with the global (g) flag: write /${pattern.source}/${pattern.flags}g, or use String.replace to replace only the first match.`,
            node,
          )
        }
        result = name === "replace" ? value.replace(pattern, replacement) : value.replaceAll(pattern, replacement)
        break
      }
      if (name === "replace") {
        result = value.replace(str(0), str(1))
        break
      }
      result = value.replaceAll(str(0), str(1))
      break
    }
    case "match": {
      const pattern = toHostRegex(args[0], name, node)
      const matched = value.match(pattern)
      if (matched === null) return null

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Add the g flag: str.replaceAll(/foo/g, 'bar')
  2. When constructing dynamically, include 'g' in flags: new RegExp(p, flags + 'g')
  3. Use String.replace(pattern, replacement) instead if only the first match should be replaced
  4. Use a plain string as the search value — replaceAll accepts strings without a g flag

Example fix

// before
text.replaceAll(/\s+/, "_")
// after
text.replaceAll(/\s+/g, "_")
// or first-match only:
text.replace(/\s+/, "_")
Defensive patterns

Strategy: validation

Validate before calling

function globalize(re) { return re instanceof RegExp && !re.global ? new RegExp(re.source, re.flags + "g") : re }
text.replaceAll(globalize(pattern), replacement)

Type guard

const isGlobalRegex = (v) => v instanceof RegExp && v.global

Try / catch

try { out = text.replaceAll(re, rep) } catch (e) { if (String(e.message).includes("global (g) flag")) out = text.replaceAll(new RegExp(re.source, re.flags + "g"), rep); else throw e }

Prevention

When it happens

Trigger: Calling str.replaceAll(/foo/, 'bar') where the regex lacks the g flag; building RegExp dynamically without including 'g' in the flags string; reusing a regex constant written for String.replace and passing it to replaceAll.

Common situations: Refactoring replace() calls to replaceAll() without updating flags; constructing new RegExp(userPattern) with default empty flags; sharing regexes between match/replace/replaceAll call sites with differing flag needs.

Related errors


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