evanw/esbuild · error · Error
Plugin at index ${i} must be an object
Error message
Plugin at index ${i} must be an object What it means
esbuild's build plugins array must be a list of plugin objects, each with at least a name and a setup function. At lib/shared/common.ts:1222 the loop over plugins checks typeof item === 'object' first; if an entry is a primitive (string, number), null, or a function, the check fails and esbuild throws with the offending index. This is a hard structural validation before name/setup are even inspected.
Source
Thrown at lib/shared/common.ts:1222
name: string,
note: () => types.Note | undefined,
callback: (args: types.OnLoadArgs) =>
(types.OnLoadResult | null | undefined | Promise<types.OnLoadResult | null | undefined>),
},
} = {}
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')View on GitHub (pinned to 6ff1d8b0d8)
Solutions
- Ensure every element of the plugins array is a plain object: filter(Boolean) before passing: plugins: [a, b].filter(Boolean).
- Wrap a single plugin in an array: plugins: [myPlugin].
- Add a TS type annotation plugins: Plugin[] so the compiler rejects non-objects.
Example fix
// before
esbuild.build({
plugins: [vuePlugin, useReact && reactPlugin], // reactPlugin is `false` when disabled
});
// after
esbuild.build({
plugins: [vuePlugin, useReact && reactPlugin].filter(Boolean) as Plugin[],
}); Defensive patterns
Strategy: validation
Validate before calling
function cleanPlugins(input) {
return (Array.isArray(input) ? input : [input])
.filter((p): p is { name: string; setup: Function } =>
!!p && typeof p === 'object' && typeof p.name === 'string' && typeof p.setup === 'function');
}
await esbuild.build({ ...opts, plugins: cleanPlugins(opts.plugins) }); Type guard
function isPluginObject(v): v is { name: string; setup: Function } {
return !!v && typeof v === 'object' && !Array.isArray(v)
&& typeof v.name === 'string' && v.name !== ''
&& typeof v.setup === 'function';
} Prevention
- Type your plugins array as Plugin[] so the compiler catches non-objects.
- Always .filter(Boolean) when conditionally including plugins.
- Wrap a single plugin in an array literal.
When it happens
Trigger: Passing plugins: 'myPlugin' (a string) or plugins: [someFunction] instead of an array of objects. Passing plugins: [{ name:'a', setup:fn }, null] (trailing null from a bad filter). Passing a single plugin object that isn't wrapped in an array (gets iterated by char if it's a string, or throws immediately).
Common situations: Conditional plugins: const plugins = [cond && {name,setup}]; the && yields false when cond is false, putting false into the array. Spreading a possibly-undefined list: plugins: [...basePlugins, maybePlugin] where maybePlugin is undefined. Forgetting to wrap: plugins: myPluginObject.
Related errors
- Plugin at index ${i} is missing a name
- Plugin is missing a setup function
- 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/5acb7b54c9f5e586.json.
Report an issue: GitHub.