colinhacks/zod · error · Error

.pick() cannot be used on object schemas containing…

Error message

.pick() cannot be used on object schemas containing refinements

What it means

Thrown by the internal pick() helper (the engine behind `.pick()`). Zod v4 attaches refinements (`.refine()`, `.check()`) to the object schema itself via `def.checks`, and `.pick()` produces a new schema with a fresh empty checks array. Silently dropping refinements during a sub-selection would be a correctness hazard, so the operation is hard-blocked whenever `def.checks.length > 0`.

Solutions

  1. Move the refinement onto the relevant leaf field or re-apply it after `.pick()` so the new schema owns it explicitly.
  2. Drop the refinement from the source object before picking (or use a refinement-free variant of the schema for the DTO).
  3. Build the picked schema from scratch and add the refinement scoped to the reduced field set.

Example fix

// before
const User = z.object({ a: z.string(), b: z.string() }).refine(v => v.a === v.b);
const Picked = User.pick({ a: true }); // throws

// after
const Picked = z.object({ a: z.string() });
// re-apply only the refinement logic that still applies
Defensive patterns

Strategy: validation

Validate before calling

function canPick(schema: z.ZodObject): boolean {
  const checks = (schema as any)._zod?.def?.checks;
  return !checks || checks.length === 0;
}
// if (!canPick(MyObject)) { /* refactor: drop refinement or rebuild */ }

Type guard

function hasObjectRefinements(schema: z.ZodObject): boolean {
  const checks = (schema as any)._zod?.def?.checks;
  return Array.isArray(checks) && checks.length > 0;
}

Prevention

When it happens

Trigger: Calling `myObject.pick({ a: true })` on an object that was built with `.refine(...)`, `.refine(...).refine(...)`, `.check(...)`, or any check that lands on the object node. The throw happens eagerly at the `.pick()` call, not at parse time.

Common situations: Building a base schema with a cross-field refinement (e.g. password/confirm equality) and then sub-selecting fields for a form subset; sharing a domain schema that carries invariants and slicing it for an API DTO; refactoring a flat schema by adding `.refine()` upstream of an existing `.pick()`.

Related errors


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

Appendix: source

Thrown at packages/zod/src/v4/core/util.ts:607

  safeint: [Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER],
  int32: [-2147483648, 2147483647],
  uint32: [0, 4294967295],
  float32: [-3.4028234663852886e38, 3.4028234663852886e38],
  float64: [-Number.MAX_VALUE, Number.MAX_VALUE],
};

export const BIGINT_FORMAT_RANGES: Record<checks.$ZodBigIntFormats, [bigint, bigint]> = {
  int64: [/* @__PURE__*/ BigInt("-9223372036854775808"), /* @__PURE__*/ BigInt("9223372036854775807")],
  uint64: [/* @__PURE__*/ BigInt(0), /* @__PURE__*/ BigInt("18446744073709551615")],
};

export function pick(schema: schemas.$ZodObject, mask: Record<string, unknown>): any {
  const currDef = schema._zod.def;

  const checks = currDef.checks;
  const hasChecks = checks && checks.length > 0;
  if (hasChecks) {
    throw new Error(".pick() cannot be used on object schemas containing refinements");
  }

  const def = mergeDefs(schema._zod.def, {
    get shape() {
      const newShape: Writeable<schemas.$ZodShape> = {};
      for (const key in mask) {
        if (!(key in currDef.shape)) {
          throw new Error(`Unrecognized key: "${key}"`);
        }
        if (!mask[key]) continue;
        newShape[key] = currDef.shape[key]!;
      }

      assignProp(this, "shape", newShape); // self-caching
      return newShape;
    },
    checks: [],
  });

View on GitHub (pinned to 2d90846af9)