colinhacks/zod · error · Error
implementAsync() must be called with a function
Error message
implementAsync() must be called with a function
What it means
Thrown by inst.implementAsync() on a $ZodFunction when the argument is not of type "function". implementAsync() is the async counterpart of implement(): it wraps a function whose argument/return parsing is awaited. The same typeof guard rejects non-callable values at the wrap site, before any promise machinery is set up.
Solutions
- Pass an async function (or any function) to implementAsync().
- Pass the function reference, not the result of calling it (no trailing parentheses).
- Guard optional handlers with a conditional before calling implementAsync().
- Verify imports resolve to actual functions in test setup.
Example fix
// before const fn = z.function(z.string(), z.string()).implementAsync(asyncHandler()); // after const fn = z.function(z.string(), z.string()).implementAsync(asyncHandler);
Defensive patterns
Strategy: type-guard
Validate before calling
function implementAsyncOrThrow<F>(fnSchema: z.ZodFunction, fn: F) {
if (typeof fn !== "function") throw new Error("implementAsync() requires a function");
return fnSchema.implementAsync(fn as any);
} Type guard
function isFunction(v: unknown): v is Function {
return typeof v === "function";
} Prevention
- Pass the function reference, not its return value (no trailing parentheses).
- Type the handler parameter as Function so tsc catches mistakes.
- Check for undefined imports before wiring async handlers.
When it happens
Trigger: Calling z.function(...).implementAsync(null), .implementAsync({}), .implementAsync(123), or passing a non-function value. Like error 53 but for the async variant; also fires when a value intended to be an async handler is undefined (e.g. a missing import or a typo in the handler name).
Common situations: Using implementAsync where implement was intended but passing a non-function; passing a Promise (the result of calling the async function) instead of the function itself; refactors that leave the handler reference undefined; mocking in tests that substitutes a plain object for the handler.
Related errors
- implement() must be called with a function
- Invalid element at key
- A discriminator value for key
- Can't use "invalid_type_error" or "required_error" in…
- Cannot create literal schema with no valid values
AI-assisted analysis of colinhacks/zod@2d90846af9 (2026-08-11).
Data as JSON: /api/errors/d159ed4c30b915ea.
Report an issue: GitHub.
Appendix: source
Thrown at packages/zod/src/v4/core/schemas.ts:4463
inst._zod.def = def;
inst.implement = (func) => {
if (typeof func !== "function") {
throw new Error("implement() must be called with a function");
}
return function (this: any, ...args: never[]) {
const parsedArgs = inst._def.input ? parse(inst._def.input, args) : args;
const result = Reflect.apply(func, this, parsedArgs as never[]);
if (inst._def.output) {
return parse(inst._def.output, result);
}
return result as any;
};
};
inst.implementAsync = (func) => {
if (typeof func !== "function") {
throw new Error("implementAsync() must be called with a function");
}
return async function (this: any, ...args: never[]) {
const parsedArgs = inst._def.input ? await parseAsync(inst._def.input, args) : args;
const result = await Reflect.apply(func, this, parsedArgs as never[]);
if (inst._def.output) {
return await parseAsync(inst._def.output, result);
}
return result;
} as any;
};
inst._zod.parse = (payload, _ctx) => {
if (typeof payload.value !== "function") {
payload.issues.push({
code: "invalid_type",
expected: "function",
input: payload.value,
inst,View on GitHub (pinned to 2d90846af9)