{"record":{"id":"5acb7b54c9f5e586","repo":"evanw/esbuild","slug":"plugin-at-index-i-must-be-an-object","errorCode":null,"errorMessage":"Plugin at index ${i} must be an object","messagePattern":"Plugin at index (.+?) must be an object","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/shared/common.ts","lineNumber":1226,"sourceCode":"      name: string,\n      note: () => types.Note | undefined,\n      callback: (args: types.OnLoadArgs) =>\n        (types.OnLoadResult | null | undefined | Promise<types.OnLoadResult | null | undefined>),\n    },\n  } = {}\n\n  let onDisposeCallbacks: (() => void)[] = []\n  let nextCallbackID = 0\n  let i = 0\n  let requestPlugins: protocol.BuildPlugin[] = []\n  let isSetupDone = false\n\n  // Clone the plugin array to guard against mutation during iteration\n  plugins = [...plugins]\n\n  for (let item of plugins) {\n    let keys: OptionKeys = {}\n    if (typeof item !== 'object') throw new Error(`Plugin at index ${i} must be an object`)\n    const name = getFlag(item, keys, 'name', mustBeString)\n    if (typeof name !== 'string' || name === '') throw new Error(`Plugin at index ${i} is missing a name`)\n    try {\n      let setup = getFlag(item, keys, 'setup', mustBeFunction)\n      if (typeof setup !== 'function') throw new Error(`Plugin is missing a setup function`)\n      checkForInvalidFlags(item, keys, `on plugin ${quote(name)}`)\n\n      let plugin: protocol.BuildPlugin = {\n        name,\n        onStart: false,\n        onEnd: false,\n        onResolve: [],\n        onLoad: [],\n      }\n      i++\n\n      let resolve = (path: string, options: types.ResolveOptions = {}): Promise<types.ResolveResult> => {\n        if (!isSetupDone) throw new Error('Cannot call \"resolve\" before plugin setup has completed')","sourceCodeStart":1208,"sourceCodeEnd":1244,"githubUrl":"https://github.com/evanw/esbuild/blob/f6058f8364fe7ab91ca57a83e02577ed74c9cae4/lib/shared/common.ts#L1208-L1244","documentation":"During plugin setup (lib/shared/common.ts:1226), esbuild iterates the `plugins` array and checks each entry with `typeof item !== 'object'`. If an element is not an object (e.g. a string, number, null, or a function), this error is thrown. Each plugin must be a plain object literal with at least `name` and `setup`.","triggerScenarios":"Passing a `plugins` array whose element is a primitive, null, or a function instead of an object — e.g. `plugins: [myPluginFn]` or `plugins: ['some-name']` or `plugins: [null]`.","commonSituations":"Confusing esbuild's plugin API with other bundlers (e.g. Rollup/Webpack where plugins are sometimes constructor/function instances); spreading a single plugin instead of wrapping it; passing a plugin factory result that returned undefined.","solutions":["Wrap each plugin as an object with a `name` string and a `setup` function: `{ name: 'my-plugin', setup(build) { ... } }`.","Check that your plugin factory/import actually returns the plugin object and not undefined or a function.","Validate the array before passing it to esbuild (see type guard)."],"exampleFix":"// before\nesbuild.build({ plugins: [myPluginSetup] });\n// after\nesbuild.build({ plugins: [{ name: 'my-plugin', setup: myPluginSetup }] });","handlingStrategy":"type-guard","validationCode":"function validatePlugins(plugins: any[]): void {\n  plugins.forEach((p, i) => {\n    if (typeof p !== 'object' || p === null) throw new Error(`Plugin at index ${i} must be an object`);\n  });\n}\nvalidatePlugins(options.plugins);","typeGuard":"function isPluginObject(v: any): v is { name: string; setup: Function } {\n  return typeof v === 'object' && v !== null && typeof v.name === 'string' && v.name !== '' && typeof v.setup === 'function';\n}","tryCatchPattern":"try {\n  await esbuild.build(options);\n} catch (e) {\n  if (/Plugin at index .* must be an object/.test(String(e.message))) { /* fix plugins array */ }\n  else throw e;\n}","preventionTips":["Always author plugins as object literals { name, setup }.","Add a unit test that type-checks your plugins array before build."],"tags":["plugins","validation","config","api-misuse"],"backgroundTag":null,"analyzedSha":"f6058f8364fe7ab91ca57a83e02577ed74c9cae4","analyzedAt":"2026-08-09T18:37:22.223Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}