evanw/esbuild · error · Error
Plugin is missing a setup function
Error message
Plugin is missing a setup function
What it means
The 'setup' function is the entry point of an esbuild plugin; esbuild calls it once per build with the BuildPlugin interface (onResolve, onLoad, onStart, onEnd, resolve, etc.). lib/shared/common.ts:1227 throws when getFlag(setup, mustBeFunction) is not a function, because there is nothing else to invoke. This is checked after name (45) and is the last structural guard before the plugin is registered.
Source
Thrown at lib/shared/common.ts:1227
} = {}
let onDisposeCallbacks: (() => void)[] = []
let nextCallbackID = 0
let i = 0
let requestPlugins: protocol.BuildPlugin[] = []
let isSetupDone = false
// Clone the plugin array to guard against mutation during iteration
plugins = [...plugins]
for (let item of plugins) {
let keys: OptionKeys = {}
if (typeof item !== 'object') throw new Error(`Plugin at index ${i} must be an object`)
const name = getFlag(item, keys, 'name', mustBeString)
if (typeof name !== 'string' || name === '') throw new Error(`Plugin at index ${i} is missing a name`)
try {
let setup = getFlag(item, keys, 'setup', mustBeFunction)
if (typeof setup !== 'function') throw new Error(`Plugin is missing a setup function`)
checkForInvalidFlags(item, keys, `on plugin ${quote(name)}`)
let plugin: protocol.BuildPlugin = {
name,
onStart: false,
onEnd: false,
onResolve: [],
onLoad: [],
}
i++
let resolve = (path: string, options: types.ResolveOptions = {}): Promise<types.ResolveResult> => {
if (!isSetupDone) throw new Error('Cannot call "resolve" before plugin setup has completed')
if (typeof path !== 'string') throw new Error(`The path to resolve must be a string`)
let keys: OptionKeys = Object.create(null)
let pluginName = getFlag(options, keys, 'pluginName', mustBeString)
let importer = getFlag(options, keys, 'importer', mustBeString)
let namespace = getFlag(options, keys, 'namespace', mustBeString)View on GitHub (pinned to 6ff1d8b0d8)
Solutions
- Define setup(build) { ... } as a top-level method on the plugin object.
- If using a class, pass new MyPlugin() (an instance) so its setup method resolves.
- Verify the key is literally 'setup' (not setupFn, init, configure).
Example fix
// before
export default {
name: 'my-plugin',
// forgot setup; only has helpers
resolveId() { /* ... */ },
};
// after
export default {
name: 'my-plugin',
setup(build) {
build.onResolve({ filter: /.*/ }, () => { /* ... */ });
},
}; Defensive patterns
Strategy: type-guard
Validate before calling
function assertPlugin(p) {
if (typeof p.setup !== 'function') {
throw new Error(`Plugin ${p.name} is missing a setup(build) function`);
}
return p;
} Type guard
function hasSetup(p): p is { name: string; setup: Function } {
return !!p && typeof p.name === 'string' && typeof p.setup === 'function';
} Prevention
- Author plugins with a literal setup(build){} method on the exported object.
- Pass instances, not classes, when using class-based plugins.
- Verify the property is literally 'setup' (not setupFn/init).
When it happens
Trigger: Plugin object with name but no setup. setup defined as an arrow stored in a const that was never assigned: const setup; { name, setup }. setup accidentally renamed (e.g. setupFunction) so the actual 'setup' key is undefined.
Common situations: Plugin written as a class whose setup is on the prototype (instance method) but the raw class is passed instead of an instance. Minifier strips an unused-looking 'setup' export. Plugin factory returns { name, onResolve } forgetting setup.
Related errors
- Plugin at index ${i} must be an object
- Plugin at index ${i} is missing a name
- Missing "kind" in ${callName}() call
- Cannot call "resolve" before plugin setup has completed
- Must specify "kind" when calling "resolve"
AI-assisted analysis of evanw/esbuild@6ff1d8b0d8 (2026-08-03).
Data as JSON: /data/errors/debda113a733eee3.json.
Report an issue: GitHub.