{"record":{"id":"0cb4c5e1ef3e7716","repo":"evanw/esbuild","slug":"cannot-call-resolve-before-plugin-setup-has-comp","errorCode":null,"errorMessage":"Cannot call \"resolve\" before plugin setup has completed","messagePattern":"Cannot call \"resolve\" before plugin setup has completed","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/shared/common.ts","lineNumber":1244,"sourceCode":"    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')\n        if (typeof path !== 'string') throw new Error(`The path to resolve must be a string`)\n        let keys: OptionKeys = Object.create(null)\n        let pluginName = getFlag(options, keys, 'pluginName', mustBeString)\n        let importer = getFlag(options, keys, 'importer', mustBeString)\n        let namespace = getFlag(options, keys, 'namespace', mustBeString)\n        let resolveDir = getFlag(options, keys, 'resolveDir', mustBeString)\n        let kind = getFlag(options, keys, 'kind', mustBeString)\n        let pluginData = getFlag(options, keys, 'pluginData', canBeAnything)\n        let importAttributes = getFlag(options, keys, 'with', mustBeObject)\n        checkForInvalidFlags(options, keys, 'in resolve() call')\n\n        return new Promise((resolve, reject) => {\n          const request: protocol.ResolveRequest = {\n            command: 'resolve',\n            path,\n            key: buildKey,\n            pluginName: name,\n          }","sourceCodeStart":1226,"sourceCodeEnd":1262,"githubUrl":"https://github.com/evanw/esbuild/blob/f6058f8364fe7ab91ca57a83e02577ed74c9cae4/lib/shared/common.ts#L1226-L1262","documentation":"Inside a plugin's `setup`, esbuild provides a `resolve()` helper that calls back into esbuild's resolver. The closure (lib/shared/common.ts:1244) guards on `isSetupDone`; calling `resolve` synchronously during setup, before esbuild has finished initializing plugins, throws this error. `resolve` is meant to be used inside onResolve/onLoad/onStart/onEnd callbacks, or after setup completes.","triggerScenarios":"Calling `build.resolve(...)` (the argument passed to `setup`) synchronously in the setup body before any hook fires, e.g. `setup(build) { build.resolve('foo', {kind:'import-statement'}) }` at the top level of setup.","commonSituations":"Misunderstanding that the `resolve` passed to setup is for use inside callbacks; pre-resolving module paths during setup; moving logic out of an onResolve hook into setup.","solutions":["Move the `resolve()` call inside an `onResolve`, `onLoad`, `onStart`, or `onEnd` callback where it is allowed.","If you need resolution at setup time, defer it with an `onStart` hook instead of calling it synchronously in setup."],"exampleFix":"// before\nsetup(build) {\n  build.resolve('./foo', { kind: 'import-statement' }); // throws\n}\n// after\nsetup(build) {\n  build.onStart(async () => {\n    const r = await build.resolve('./foo', { kind: 'import-statement' });\n    // use r\n    return null;\n  });\n}","handlingStrategy":"validation","validationCode":"// Structural guard: never call build.resolve() at the top level of setup.\n// Only call it inside onStart/onResolve/onLoad/onEnd callbacks.","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat the resolve() passed to setup as callback-only.","Use onStart for setup-time resolution needs."],"tags":["plugins","api-misuse","resolve","lifecycle"],"backgroundTag":null,"analyzedSha":"f6058f8364fe7ab91ca57a83e02577ed74c9cae4","analyzedAt":"2026-08-09T18:37:22.223Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}