evanw/esbuild · error · Error
Expected onLoad() callback in plugin ${quote(name)} to retur
Error message
Expected onLoad() callback in plugin ${quote(name)} to return an object What it means
An onLoad callback returns { contents?, loader?, resolveDir?, errors?, warnings?, ... } describing the loaded module, or nothing to defer. lib/shared/common.ts:1446 throws when the return is a non-null non-object. Returning a bare string of source (a very common mistake) is rejected; contents must be wrapped in an object and must be a string or Uint8Array.
Source
Thrown at lib/shared/common.ts:1446
}
sendResponse(id, response as any)
}
requestCallbacks['on-load'] = async (id, request: protocol.OnLoadRequest) => {
let response: protocol.OnLoadResponse = {}, name = '', callback, note
for (let id of request.ids) {
try {
({ name, callback, note } = onLoadCallbacks[id])
let result = await callback({
path: request.path,
namespace: request.namespace,
suffix: request.suffix,
pluginData: details.load(request.pluginData),
with: request.with,
})
if (result != null) {
if (typeof result !== 'object') throw new Error(`Expected onLoad() callback in plugin ${quote(name)} to return an object`)
let keys: OptionKeys = {}
let pluginName = getFlag(result, keys, 'pluginName', mustBeString)
let contents = getFlag(result, keys, 'contents', mustBeStringOrUint8Array)
let resolveDir = getFlag(result, keys, 'resolveDir', mustBeString)
let pluginData = getFlag(result, keys, 'pluginData', canBeAnything)
let loader = getFlag(result, keys, 'loader', mustBeString)
let errors = getFlag(result, keys, 'errors', mustBeArray)
let warnings = getFlag(result, keys, 'warnings', mustBeArray)
let watchFiles = getFlag(result, keys, 'watchFiles', mustBeArrayOfStrings)
let watchDirs = getFlag(result, keys, 'watchDirs', mustBeArrayOfStrings)
checkForInvalidFlags(result, keys, `from onLoad() callback in plugin ${quote(name)}`)
response.id = id
if (pluginName != null) response.pluginName = pluginName
if (contents instanceof Uint8Array) response.contents = contents
else if (contents != null) response.contents = protocol.encodeUTF8(contents)
if (resolveDir != null) response.resolveDir = resolveDir
if (pluginData != null) response.pluginData = details.store(pluginData)View on GitHub (pinned to 6ff1d8b0d8)
Solutions
- Wrap the contents: onLoad(args => ({ contents: readFileSync(args.path, 'utf8'), loader: 'ts' })).
- For binary contents, return { contents: uint8array }.
- Return undefined to let esbuild's default loader take over.
Example fix
// before
build.onLoad({ filter: /\.txt$/ }, async args => {
return await fs.readFile(args.path, 'utf8');
});
// after
build.onLoad({ filter: /\.txt$/ }, async args => {
return { contents: await fs.readFile(args.path, 'utf8'), loader: 'text' };
}); Defensive patterns
Strategy: validation
Validate before calling
function wrapOnLoad(build, opts, cb) {
build.onLoad(opts, async (args) => {
const r = await cb(args);
if (r != null && typeof r !== 'object') {
throw new TypeError('onLoad callback must return { contents, loader?, ... } or void');
}
return r as any;
});
} Type guard
function isLoadResult(v): v is import('esbuild').OnLoadResult | null | undefined {
return v == null || (typeof v === 'object' && typeof (v as any).then !== 'function');
} Prevention
- Always wrap source text: return { contents, loader }.
- Return undefined to let esbuild's default loader handle the file.
- Type the callback return as OnLoadResult | void.
When it happens
Trigger: onLoad(args => readFileSync(args.path, 'utf8')) — returns a string. onLoad(args => new Uint8Array(...)) — returns a Uint8Array directly. Returning a Promise<string>.
Common situations: Plugin that inlines virtual files returns the file text directly. Porting a loader whose convention was to return source as a string. Author forgets the wrapper { contents }.
Related errors
- onLoad() call is missing a filter
- Expected onStart() callback in plugin ${quote(name)} to retu
- Expected onResolve() callback in plugin ${quote(name)} to re
- Expected onEnd() callback in plugin ${quote(name)} to return
- Plugin at index ${i} must be an object
AI-assisted analysis of evanw/esbuild@6ff1d8b0d8 (2026-08-03).
Data as JSON: /data/errors/d9c3d274a01858bc.json.
Report an issue: GitHub.