{"id":"306d1a9a1d5a4384","repo":"evanw/esbuild","slug":"s-q-filter-is-not-a-valid-go-regular-expressio","errorCode":null,"errorMessage":"[%s] %q filter is not a valid Go regular expression: %q","messagePattern":"\\[(.+?)\\] %q filter is not a valid Go regular expression: %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/config.go","lineNumber":763,"sourceCode":"\n\t// Cache for next time\n\tfilterMutex.Lock()\n\tdefer filterMutex.Unlock()\n\tif filterCache == nil {\n\t\tfilterCache = make(map[string]*regexp.Regexp)\n\t}\n\tfilterCache[filter] = result\n\treturn\n}\n\nfunc CompileFilterForPlugin(pluginName string, kind string, filter string) (*regexp.Regexp, error) {\n\tif filter == \"\" {\n\t\treturn nil, fmt.Errorf(\"[%s] %q is missing a filter\", pluginName, kind)\n\t}\n\n\tresult := compileFilter(filter)\n\tif result == nil {\n\t\treturn nil, fmt.Errorf(\"[%s] %q filter is not a valid Go regular expression: %q\", pluginName, kind, filter)\n\t}\n\n\treturn result, nil\n}\n\nfunc PluginAppliesToPath(path logger.Path, filter *regexp.Regexp, namespace string) bool {\n\treturn (namespace == \"\" || path.Namespace == namespace) && filter.MatchString(path.Text)\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Plugin API\n\ntype Plugin struct {\n\tName      string\n\tOnStart   []OnStart\n\tOnResolve []OnResolve\n\tOnLoad    []OnLoad\n}","sourceCodeStart":745,"sourceCodeEnd":781,"githubUrl":"https://github.com/evanw/esbuild/blob/6ff1d8b0d8c134e867a397eef39702a223ebef9e/internal/config/config.go#L745-L781","documentation":"Returned by config.CompileFilterForPlugin when a plugin's OnResolve/OnLoad filter is a non-empty string that fails Go's regexp.Compile (RE2 syntax). esbuild precompiles filters for performance and caches them, so a syntactically bad regex is caught at plugin-registration time. The offending filter is echoed in the message.","triggerScenarios":"Pass a filter containing PCRE-only constructs unsupported by RE2 (e.g. lookahead '(?=...)', backreferences, or an unbalanced parenthesis). Examples: filter: 'foo(bar', filter: '(?<=x)', filter: '[z-a]' (invalid range). Fires for OnResolve and OnLoad registrations in JS or Go plugin setup.","commonSituations":"Copying a JavaScript RegExp literal into the filter string that uses lookbehind/lookahead (JS supports these, Go RE2 does not); pasting a regex from a Stack Overflow answer that uses backreferences; version differences where a previously-tolerant engine accepted the pattern but RE2 rejects it.","solutions":["Rewrite the regex in RE2-compatible syntax (no lookahead, no lookbehind, no backreferences).","Test the pattern with Go's regexp playground or `regexp.Compile` before passing it as a filter.","If you need lookahead semantics, move that logic inside the callback and use a broader filter.","Validate filter strings at plugin-author time with a unit test that compiles them."],"exampleFix":"// before\nb.onResolve({ filter: 'foo(?=bar)' }, fn)  // lookahead unsupported by RE2\n\n// after\nb.onResolve({ filter: 'foobar' }, fn)  // match literally; or do lookahead inside fn","handlingStrategy":"validation","validationCode":"// Pre-compile the filter with Go-compatible RE2 semantics where possible.\n// In Node there is no RE2 by default, but you can at least sanity-check balance:\nfunction looksLikeBalancedRegex(s) {\n  let depth = 0\n  for (const ch of s) {\n    if (ch === '(') depth++\n    if (ch === ')') depth--\n    if (depth < 0) return false\n  }\n  return depth === 0\n}\nif (!looksLikeBalancedRegex(filter)) throw new Error('Filter looks unbalanced: ' + filter)","typeGuard":"function isSafeEsbuildFilter(s: string): boolean {\n  return s.length > 0 && !/(\\(\\?<=)|(\\(\\?=)|(\\(\\?!)|(\\(\\?<!)|\\\\\\d)/.test(s)\n}","tryCatchPattern":"try {\n  await esbuild.build({ plugins })\n} catch (e) {\n  if (/not a valid Go regular expression/i.test(e.message)) {\n    console.error('Plugin filter is not RE2-compatible:', e.message)\n    // identify the offending plugin via the bracketed [name] prefix\n  }\n  throw e\n}","preventionTips":["Avoid lookahead/lookbehind/backreferences in esbuild plugin filters.","Keep filters minimal — match a file extension or namespace, not a complex expression.","Unit-test filters against Go regexp.Compile (e.g. via a tiny Go helper or the 're2' npm package) in CI."],"tags":["plugin","filter","regex","re2","config"],"analyzedSha":"6ff1d8b0d8c134e867a397eef39702a223ebef9e","analyzedAt":"2026-08-03T19:42:38.433Z","schemaVersion":2}