evanw/esbuild · error · Error
Missing "kind" in ${callName}() call
Error message
Missing "kind" in ${callName}() call What it means
esbuild's formatMessages() requires an options object whose 'kind' field tells esbuild whether to format the messages as errors or as warnings (the formatting differs in severity prefix). The check at lib/shared/common.ts:795 fires when 'kind' is undefined after getFlag() extracts it, meaning the caller passed an options object but omitted the mandatory field. esbuild refuses to guess because error vs. warning formatting is semantically meaningful for terminal output and CI exit codes.
Source
Thrown at lib/shared/common.ts:795
callback(failureErrorWithLog('Transform failed', [error], []), null)
})
}
}
if ((typeof input === 'string' || input instanceof Uint8Array) && input.length > 1024 * 1024) {
let next = start
start = () => fs.writeFile(input, next)
}
start(null)
}
let formatMessages: StreamService['formatMessages'] = ({ callName, refs, messages, options, callback }) => {
if (!options) throw new Error(`Missing second argument in ${callName}() call`)
let keys: OptionKeys = {}
let kind = getFlag(options, keys, 'kind', mustBeString)
let color = getFlag(options, keys, 'color', mustBeBoolean)
let terminalWidth = getFlag(options, keys, 'terminalWidth', mustBeInteger)
checkForInvalidFlags(options, keys, `in ${callName}() call`)
if (kind === void 0) throw new Error(`Missing "kind" in ${callName}() call`)
if (kind !== 'error' && kind !== 'warning') throw new Error(`Expected "kind" to be "error" or "warning" in ${callName}() call`)
let request: protocol.FormatMsgsRequest = {
command: 'format-msgs',
messages: sanitizeMessages(messages, 'messages', null, '', terminalWidth),
isWarning: kind === 'warning',
}
if (color !== void 0) request.color = color
if (terminalWidth !== void 0) request.terminalWidth = terminalWidth
sendRequest<protocol.FormatMsgsRequest, protocol.FormatMsgsResponse>(refs, request, (error, response) => {
if (error) return callback(new Error(error), null)
callback(null, response!.messages)
})
}
let analyzeMetafile: StreamService['analyzeMetafile'] = ({ callName, refs, metafile, options, callback }) => {
if (options === void 0) options = {}
let keys: OptionKeys = {}
let color = getFlag(options, keys, 'color', mustBeBoolean)View on GitHub (pinned to 6ff1d8b0d8)
Solutions
- Pass options: { kind: 'error' } or { kind: 'warning' } as the second argument to formatMessages().
- If you built the options object programmatically, assert the 'kind' key is present before calling.
- Upgrade @types/esbuild / esbuild to a version matching the runtime so the TS signature (kind: 'error' | 'warning', required) is enforced at compile time.
Example fix
// before
await esbuild.formatMessages(msgs, { color: true });
// after
await esbuild.formatMessages(msgs, { kind: 'error', color: true }); Defensive patterns
Strategy: validation
Validate before calling
import type { FormatMessagesOptions } from 'esbuild';
function safeFormat(messages, opts) {
if (!opts || (opts.kind !== 'error' && opts.kind !== 'warning')) {
throw new TypeError("formatMessages requires options.kind = 'error' | 'warning'");
}
return esbuild.formatMessages(messages, opts);
} Type guard
function isFormatKind(v): v is 'error' | 'warning' {
return v === 'error' || v === 'warning';
} Prevention
- Treat the second argument to formatMessages as a required, fully-typed object; do not pass partial config.
- Lock the TS types from the installed esbuild version so the compiler enforces kind.
- Wrap formatMessages in a project helper that validates kind once.
When it happens
Trigger: Calling esbuild.formatMessages(messages, {}) with no 'kind'. Calling it with options that set color or terminalWidth but forget kind. Passing options whose kind is not a string (getFlag returns undefined for non-strings via mustBeString), e.g. kind: 1 or kind: null.
Common situations: Devs copy the analyzeMetafile() signature (where options and most fields are optional) onto formatMessages(). IDE autocomplete suggests 'color' and 'terminalWidth' first; devs submit early. Migration from an older API that defaulted kind. Generating the options object dynamically from a config map that doesn't include 'kind'.
Related errors
- Plugin at index ${i} must be an object
- Plugin at index ${i} is missing a name
- Plugin is missing a setup function
- Cannot call "resolve" before plugin setup has completed
- Must specify "kind" when calling "resolve"
AI-assisted analysis of evanw/esbuild@6ff1d8b0d8 (2026-08-03).
Data as JSON: /data/errors/536769ac201eaf49.json.
Report an issue: GitHub.