colinhacks/zod · error · Error

You must pass an array of schemas to z.tuple([ ... ])

Error message

You must pass an array of schemas to z.tuple([ ... ])

What it means

Thrown by ZodTuple.create (packages/zod/src/v3/types.ts:3468) when the first argument is not an array. The v3 API requires the schemas to be passed as a literal array — z.tuple([z.string(), z.number()]) — both for TypeScript tuple inference and because the runtime builds the items list from array indices. Passing the schemas as spread arguments or a non-array value defeats the build.

Solutions

  1. Wrap the schemas in an array literal: `z.tuple([z.string(), z.number()])`.
  2. If building dynamically, ensure the variable is a real array before passing it: `z.tuple(items as [ZodType, ...ZodType[]])`.
  3. For spreads, materialize the array first (`const items = [...a, ...b]; z.tuple(items)`).
  4. If calling from JS, run a defensive `Array.isArray(schemas)` check before construction.

Example fix

// before
const pair = z.tuple(z.string(), z.number());

// after
const pair = z.tuple([z.string(), z.number()]);
Defensive patterns

Strategy: validation

Validate before calling

import { ZodType } from 'zod';

function assertTupleSchemas(schemas: unknown): asserts schemas is ZodType[] {
  if (!Array.isArray(schemas)) {
    throw new TypeError(`z.tuple() expects an array, got ${typeof schemas}`);
  }
}

Type guard

import { ZodTypeAny } from 'zod';

function isZodTypeArray(v: unknown): v is ZodTypeAny[] {
  return Array.isArray(v) && v.every((x) => x instanceof ZodTypeAny || (x && typeof x === 'object' && '_def' in x));
}

Try / catch

null

Prevention

When it happens

Trigger: Calling `z.tuple(z.string(), z.number())` (missing the array), `z.tuple(someObject)`, or `z.tuple(...someIterable)` where the argument does not satisfy Array.isArray. TypeScript usually catches the shape, but loose any-typed or JS callers hit the runtime guard.

Common situations: Migrating from another API that takes variadic args; passing a readonly tuple type without conversion; building the schema list dynamically and forgetting to wrap in an array; calling from plain JavaScript where the type signature is not enforced.

Related errors


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

Appendix: source

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

  }

  get items() {
    return this._def.items;
  }

  rest<RestSchema extends ZodTypeAny>(rest: RestSchema): ZodTuple<T, RestSchema> {
    return new ZodTuple({
      ...this._def,
      rest,
    });
  }

  static create = <Items extends [ZodTypeAny, ...ZodTypeAny[]] | []>(
    schemas: Items,
    params?: RawCreateParams
  ): ZodTuple<Items, null> => {
    if (!Array.isArray(schemas)) {
      throw new Error("You must pass an array of schemas to z.tuple([ ... ])");
    }
    return new ZodTuple({
      items: schemas,
      typeName: ZodFirstPartyTypeKind.ZodTuple,
      rest: null,
      ...processCreateParams(params),
    });
  };
}

/////////////////////////////////////////
/////////////////////////////////////////
//////////                     //////////
//////////      ZodRecord      //////////
//////////                     //////////
/////////////////////////////////////////
/////////////////////////////////////////
export interface ZodRecordDef<Key extends KeySchema = ZodString, Value extends ZodTypeAny = ZodTypeAny>

View on GitHub (pinned to 2d90846af9)