colinhacks/zod · error · ZodError

invalid_return_type

invalid_return_type

Error message

Invalid function return type

What it means

Thrown as a ZodError with code 'invalid_return_type' at packages/zod/src/v3/types.ts:3897 when a function wrapped by z.function() returns a value that fails the configured returns schema. After applying the implementation, the wrapper parses the result through the returns schema and surfaces any mismatch as this ZodError, protecting callers from contract violations inside the implementation.

Source

Thrown at packages/zod/src/v3/types.ts:3897

            error.addIssue(makeReturnsIssue(result, e));
            throw error;
          });
        return parsedReturns;
      });
    } else {
      // Would love a way to avoid disabling this rule, but we need
      // an alias (using an arrow function was what caused 2651).
      // eslint-disable-next-line @typescript-eslint/no-this-alias
      const me = this;
      return OK(function (this: any, ...args: any[]) {
        const parsedArgs = me._def.args.safeParse(args, params);
        if (!parsedArgs.success) {
          throw new ZodError([makeArgsIssue(args, parsedArgs.error)]);
        }
        const result = Reflect.apply(fn, this, parsedArgs.data);
        const parsedReturns = me._def.returns.safeParse(result, params);
        if (!parsedReturns.success) {
          throw new ZodError([makeReturnsIssue(result, parsedReturns.error)]);
        }
        return parsedReturns.data;
      }) as any;
    }
  }

  parameters() {
    return this._def.args;
  }

  returnType() {
    return this._def.returns;
  }

  args<Items extends Parameters<(typeof ZodTuple)["create"]>[0]>(
    ...items: Items
  ): ZodFunction<ZodTuple<Items, ZodUnknown>, Returns> {
    return new ZodFunction({

View on GitHub (pinned to 2d90846af9)

Solutions

  1. Read the ZodError.issues path to see which return constraint failed.
  2. Fix the implementation so every code path returns a value matching the returns schema.
  3. If the real return type legitimately differs, widen/narrow the returns schema to match reality.
  4. For async implementations, ensure the returned Promise resolves (not rejects) to a conforming value and that implement() is awaited.

Example fix

// before
const fn = z
  .function()
  .args(z.string())
  .returns(z.number())
  .implement((s) => s.length > 5); // returns boolean

// after
const fn = z
  .function()
  .args(z.string())
  .returns(z.number())
  .implement((s) => s.length);
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate the implementation's return value during development.
function verifyReturns(fnReturns: z.ZodType, impl: (...args: any[]) => unknown) {
  return (...args: any[]) => {
    const result = impl(...args);
    const parsed = fnReturns.safeParse(result);
    if (!parsed.success) {
      throw new Error(`Implementation returned invalid value: ${parsed.error.message}`);
    }
    return parsed.data;
  };
}

Type guard

null

Try / catch

import { ZodError } from 'zod';

try {
  fn('count');
} catch (e) {
  if (e instanceof ZodError && e.issues.some((i) => i.code === 'invalid_return_type')) {
    // implementation broke its return contract
    logReturnBug(e.issues);
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Defining `const fn = z.function().args(z.string()).returns(z.number()).implement((s) => s.length > 5)` where the implementation returns a boolean instead of a number; any case where the implement() body yields a value outside the declared return schema.

Common situations: The implementation has a bug and returns the wrong type (e.g. forgets to coerce, returns undefined on an early-return path); the returns schema was tightened but the body wasn't updated; async implementations that resolve to the wrong shape; third-party implementations that don't honour the contract.

Related errors


AI-assisted analysis of colinhacks/zod@2d90846af9 (2026-08-11). Data as JSON: /api/errors/7a73b8f44277b4f8. Report an issue: GitHub.