{"id":"1cfb89bba5c3a3af","repo":"evanw/esbuild","slug":"s-q-is-missing-a-filter","errorCode":null,"errorMessage":"[%s] %q is missing a filter","messagePattern":"\\[(.+?)\\] %q is missing a filter","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/config.go","lineNumber":758,"sourceCode":"\t// Cache miss\n\tresult, err := regexp.Compile(filter)\n\tif err != nil {\n\t\treturn nil\n\t}\n\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 {","sourceCodeStart":740,"sourceCodeEnd":776,"githubUrl":"https://github.com/evanw/esbuild/blob/6ff1d8b0d8c134e867a397eef39702a223ebef9e/internal/config/config.go#L740-L776","documentation":"Returned by config.CompileFilterForPlugin when a plugin's OnResolve or OnLoad callback is registered with an empty Filter string. esbuild uses the filter as a precompiled Go regular expression to cheaply decide which import paths invoke the callback; an empty filter is rejected because it would either match nothing useful or force the callback to run on every path (a performance footgun). The error names the plugin and the callback kind ('OnResolve' or 'OnLoad').","triggerScenarios":"Register a plugin whose setup() calls onResolve({ filter: '', namespace: ... }, fn) or onLoad({ filter: '', namespace: ... }, fn) with an empty/missing filter. Reproduces in both the JS API (via the service protocol) and the Go API (pkg/api). Triggered during build context creation, before any file is bundled.","commonSituations":"Migrating a webpack/rollup plugin to esbuild and forgetting esbuild mandates a regex filter; building a plugin dynamically where the filter variable is conditionally empty; assuming filter is optional (it is required for onResolve/onLoad).","solutions":["Provide a non-empty Go RE2 regex for the filter, e.g. filter: '\\.css$' or a catch-all filter: '.' if you truly want every path.","If the callback should apply to a specific namespace only, still supply a filter (use '.' to match all) plus the namespace option.","Double-check that the filter variable is not conditionally set to '' by a config-driven code path.","Test the plugin in isolation to surface the error before wiring it into a larger build pipeline."],"exampleFix":"// before\nbuild({ plugins: [{ name: 'x', setup(b) { b.onResolve({ filter: '' }, () => {...}) } }] })\n\n// after\nbuild({ plugins: [{ name: 'x', setup(b) { b.onResolve({ filter: /\\.css$/ }, () => {...}) } }] })","handlingStrategy":"validation","validationCode":"// Reject plugin registrations with empty filters before build.\nfunction assertFilter(plugin, kind, filter) {\n  if (typeof filter !== 'string' || filter.length === 0) {\n    throw new Error(`Plugin ${plugin}: ${kind} requires a non-empty regex filter`)\n  }\n}","typeGuard":"function isNonEmptyFilter(f: unknown): f is string {\n  return typeof f === 'string' && f.length > 0\n}","tryCatchPattern":"try {\n  await esbuild.build({ plugins, ... })\n} catch (e) {\n  if (/missing a filter/i.test(e.message)) {\n    console.error('A plugin callback was registered without a filter:', e.message)\n    // surface plugin name from the message and patch its setup()\n  }\n  throw e\n}","preventionTips":["Always pair onResolve/onLoad with a filter; use '.' to match everything if unsure.","Author a tiny plugin-test harness that builds with a no-op entry to catch filter errors early.","Type plugin option filters as a branded NonEmptyString to make emptiness a compile error."],"tags":["plugin","filter","regex","onresolve","onload","config"],"analyzedSha":"6ff1d8b0d8c134e867a397eef39702a223ebef9e","analyzedAt":"2026-08-03T19:42:38.433Z","schemaVersion":2}