{"id":"f65c5733482581be","repo":"evanw/esbuild","slug":"expected-onend-callback-in-plugin-quote-name","errorCode":null,"errorMessage":"Expected onEnd() callback in plugin ${quote(name)} to return an object","messagePattern":"Expected onEnd\\(\\) callback in plugin (.+?) to return an object","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/shared/common.ts","lineNumber":1496,"sourceCode":"  }\n\n  let runOnEndCallbacks: RunOnEndCallbacks = (result, done) => done([], [])\n\n  if (onEndCallbacks.length > 0) {\n    runOnEndCallbacks = (result, done) => {\n      (async () => {\n        const onEndErrors: types.Message[] = []\n        const onEndWarnings: types.Message[] = []\n\n        for (const { name, callback, note } of onEndCallbacks) {\n          let newErrors: types.Message[] | undefined\n          let newWarnings: types.Message[] | undefined\n\n          try {\n            const value = await callback(result)\n\n            if (value != null) {\n              if (typeof value !== 'object') throw new Error(`Expected onEnd() callback in plugin ${quote(name)} to return an object`)\n              let keys: OptionKeys = {}\n              let errors = getFlag(value, keys, 'errors', mustBeArray)\n              let warnings = getFlag(value, keys, 'warnings', mustBeArray)\n              checkForInvalidFlags(value, keys, `from onEnd() callback in plugin ${quote(name)}`)\n\n              if (errors != null) newErrors = sanitizeMessages(errors, 'errors', details, name, undefined)\n              if (warnings != null) newWarnings = sanitizeMessages(warnings, 'warnings', details, name, undefined)\n            }\n          } catch (e) {\n            newErrors = [extractErrorMessageV8(e, streamIn, details, note && note(), name)]\n          }\n\n          // Try adding the errors and warnings to the result object, but\n          // continue if something goes wrong. If error-reporting has errors\n          // then nothing can help us...\n          if (newErrors) {\n            onEndErrors.push(...newErrors)\n            try {","sourceCodeStart":1478,"sourceCodeEnd":1514,"githubUrl":"https://github.com/evanw/esbuild/blob/6ff1d8b0d8c134e867a397eef39702a223ebef9e/lib/shared/common.ts#L1478-L1514","documentation":"An onEnd callback receives the final BuildResult and may return { errors?, warnings? } to amend the build's reported messages. lib/shared/common.ts:1496 throws when the callback returns a non-null non-object — e.g. a boolean indicating success, a status string, or a Promise resolving to a primitive. The result-amendment protocol requires the object shape so messages can be sanitised and merged.","triggerScenarios":"onEnd(() => true), onEnd(() => 'ok'), or async onEnd(async () => 'ok'). Returning the raw result of a validation lib that yields a boolean.","commonSituations":"Plugin performs post-build validation and returns true/false to signal pass/fail instead of returning { errors }. Refactor that surfaces a status code. Author confuses onEnd with a lifecycle hook that returns void.","solutions":["Return void (undefined) when there's nothing to amend.","Return { errors: [...] } or { warnings: [...] } to add messages.","If signalling failure, convert booleans to { errors: [{ text: '...' }] }."],"exampleFix":"// before\nbuild.onEnd(result => {\n  return validate(result.outputFiles);\n});\n// after\nbuild.onEnd(result => {\n  const problems = validate(result.outputFiles);\n  return problems.length ? { errors: problems.map(p => ({ text: p })) } : undefined;\n});","handlingStrategy":"validation","validationCode":"function wrapOnEnd(build, cb) {\n  build.onEnd(async (result) => {\n    const v = await cb(result);\n    if (v != null && typeof v !== 'object') {\n      throw new TypeError('onEnd callback must return { errors?, warnings? } or void');\n    }\n    return v as any;\n  });\n}","typeGuard":"function isEndResult(v): v is { errors?: any[]; warnings?: any[] } {\n  return v == null || (typeof v === 'object' && !Array.isArray(v));\n}","tryCatchPattern":null,"preventionTips":["Return undefined or { errors, warnings } from onEnd.","Convert validation booleans into { errors: [{ text }] }.","Type the callback as (result) => Promise<void | { errors?; warnings? }>."],"tags":["plugins","onend","return-value","validation"],"analyzedSha":"6ff1d8b0d8c134e867a397eef39702a223ebef9e","analyzedAt":"2026-08-03T19:42:38.433Z","schemaVersion":2}