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

  1. Pass an async function (or any function) to implementAsync().
  2. Pass the function reference, not the result of calling it (no trailing parentheses).
  3. Guard optional handlers with a conditional before calling implementAsync().
  4. 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

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


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)