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
- Wrap the schemas in an array literal: `z.tuple([z.string(), z.number()])`.
- If building dynamically, ensure the variable is a real array before passing it: `z.tuple(items as [ZodType, ...ZodType[]])`.
- For spreads, materialize the array first (`const items = [...a, ...b]; z.tuple(items)`).
- 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
- Always call z.tuple as z.tuple([...]) with an array literal.
- When building the items list dynamically, materialise it into a real array variable first.
- In TypeScript, enable strict checks so non-array arguments fail at compile time.
- For JS callers, run a defensive Array.isArray check before construction.
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
- A discriminator value for key
- Can't use "invalid_type_error" or "required_error" in…
- Cannot create literal schema with no valid values
- Discriminator property
- Duplicate discriminator value
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)