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(func)` on a `z.function()` schema when the argument is not a function. `.implementAsync()` is the async variant of `.implement()`, returning an async function whose arguments/return are parsed with `parseAsync`; it still requires a function argument to wrap.

Source

Thrown at packages/zod/src/v4/core/schemas.ts:4446

    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 912f0f51b0)

Solutions

  1. Pass a function (sync or async) to `.implementAsync()`, e.g. `schema.implementAsync(async (arg) => ...)`.
  2. Guard dynamically: `if (typeof handler === 'function') schema.implementAsync(handler)`.
  3. Verify the handler is defined at the call site (check imports and initialization order).

Example fix

// before
const fn = z.function(z.string(), z.boolean()).implementAsync(undefined);

// after
const fn = z.function(z.string(), z.boolean()).implementAsync(async (s) => !!s);
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof handler !== 'function') throw new Error('handler must be a function');
const wrapped = fnSchema.implementAsync(handler);

Type guard

function isFunction(v): boolean { return typeof v === 'function'; }

Try / catch

try {
  const wrapped = fnSchema.implementAsync(handler);
} catch (e) {
  if (e instanceof Error && e.message === 'implementAsync() must be called with a function') {
    // confirm handler is a function and retry
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling `.implementAsync(undefined)`, `.implementAsync(null)`, `.implementAsync('handler')`, or any non-function value. Same shape as the sync variant.

Common situations: Mistakenly passing a promise or a config object; handler variable is undefined due to a circular import or hoisting issue.

Related errors


AI-assisted analysis of colinhacks/zod@912f0f51b0 (2026-08-03). Data as JSON: /data/errors/d159ed4c30b915ea.json. Report an issue: GitHub.