{"record":{"id":"da56e5a5331c0cc6","repo":"evanw/esbuild","slug":"expected-onresolve-callback-in-plugin-quote-na","errorCode":null,"errorMessage":"Expected onResolve() callback in plugin ${quote(name)} to return an object","messagePattern":"Expected onResolve\\(\\) callback in plugin (.+?) to return an object","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/shared/common.ts","lineNumber":1399,"sourceCode":"  }\n\n  requestCallbacks['on-resolve'] = async (id, request: protocol.OnResolveRequest) => {\n    let response: protocol.OnResolveResponse = {}, name = '', callback, note\n    for (let id of request.ids) {\n      try {\n        ({ name, callback, note } = onResolveCallbacks[id])\n        let result = await callback({\n          path: request.path,\n          importer: request.importer,\n          namespace: request.namespace,\n          resolveDir: request.resolveDir,\n          kind: request.kind,\n          pluginData: details.load(request.pluginData),\n          with: request.with,\n        })\n\n        if (result != null) {\n          if (typeof result !== 'object') throw new Error(`Expected onResolve() callback in plugin ${quote(name)} to return an object`)\n          let keys: OptionKeys = {}\n          let pluginName = getFlag(result, keys, 'pluginName', mustBeString)\n          let path = getFlag(result, keys, 'path', mustBeString)\n          let namespace = getFlag(result, keys, 'namespace', mustBeString)\n          let suffix = getFlag(result, keys, 'suffix', mustBeString)\n          let external = getFlag(result, keys, 'external', mustBeBoolean)\n          let sideEffects = getFlag(result, keys, 'sideEffects', mustBeBoolean)\n          let pluginData = getFlag(result, keys, 'pluginData', canBeAnything)\n          let errors = getFlag(result, keys, 'errors', mustBeArray)\n          let warnings = getFlag(result, keys, 'warnings', mustBeArray)\n          let watchFiles = getFlag(result, keys, 'watchFiles', mustBeArrayOfStrings)\n          let watchDirs = getFlag(result, keys, 'watchDirs', mustBeArrayOfStrings)\n          checkForInvalidFlags(result, keys, `from onResolve() callback in plugin ${quote(name)}`)\n\n          response.id = id\n          if (pluginName != null) response.pluginName = pluginName\n          if (path != null) response.path = path\n          if (namespace != null) response.namespace = namespace","sourceCodeStart":1381,"sourceCodeEnd":1417,"githubUrl":"https://github.com/evanw/esbuild/blob/f6058f8364fe7ab91ca57a83e02577ed74c9cae4/lib/shared/common.ts#L1381-L1417","documentation":"When an `onResolve` callback runs (lib/shared/common.ts:1399), its awaited return value must be `null`/`undefined` (skip/defer) or an object describing the resolution (fields like `path`, `namespace`, `external`, `errors`, etc.). A truthy non-object (string, number, array, boolean) triggers this error, which is caught and returned as a resolve error for the plugin.","triggerScenarios":"An onResolve callback that returns a string path or other non-object instead of `{ path: ... }`.","commonSituations":"Returning a bare path string instead of an object; returning the args object directly without reshaping; confusion with bundlers where handlers return strings.","solutions":["Return an object such as `{ path: resolvedPath, namespace: 'file' }`, or `null` to defer to the next handler.","Return `{ external: true }` to mark the import external, or `{ errors: [...] }` to report a failure."],"exampleFix":"// before\nbuild.onResolve({ filter: /.*/ }, args => args.path.replace(/^app:/, ''));\n// after\nbuild.onResolve({ filter: /.*/ }, args => ({ path: args.path.replace(/^app:/, '') }));","handlingStrategy":"type-guard","validationCode":"function wrapOnResolve(cb) {\n  return async (args) => { const r = await cb(args); if (r != null && typeof r !== 'object') throw new Error('onResolve must return object or null'); return r; };\n}","typeGuard":"function isOnResolveResult(v: any): v is { path?: string; namespace?: string; external?: boolean } | null {\n  return v == null || (typeof v === 'object' && !Array.isArray(v));\n}","tryCatchPattern":null,"preventionTips":["Always return an object literal { path } or null.","Never return a bare path string."],"tags":["plugins","onresolve","validation","callback-contract"],"backgroundTag":null,"analyzedSha":"f6058f8364fe7ab91ca57a83e02577ed74c9cae4","analyzedAt":"2026-08-09T18:37:22.223Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}