colinhacks/zod · error · Error

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

Error message

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

What it means

Thrown by `util.pick` (the implementation behind `z.object(...).pick({...})`) when the object schema has refinements attached via `.refine()`, `.superRefine()`, or any check in `def.checks`. Picking a subset of keys cannot safely carry over whole-object refinements (which may reference the dropped keys), so Zod refuses rather than silently producing an unsound schema. The check happens at definition time, before the picked shape is built.

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

Solutions

  1. Move the refinement OFF the base schema and onto a derived schema after `.pick()`/`.omit()`, so the base is refinement-free and pickable.
  2. If you need both, define the raw shape, pick/omit it, then attach `.refine(...)` to the picked result.
  3. Alternatively re-implement the relevant subset of the refinement as a new `.refine()` on the picked schema that only references the remaining keys.

Example fix

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

// after — refine AFTER picking
const Shape = z.object({ a: z.string(), b: z.string() });
const Picked = Shape.pick({ a: true });
const Base = Shape.refine((v) => v.a === v.b);
Defensive patterns

Strategy: validation

Validate before calling

function isRefinementFree(schema) {
  const checks = schema._zod?.def?.checks;
  return !checks || checks.length === 0;
}
if (!isRefinementFree(objSchema)) throw new Error('cannot .pick() a refined object; refine after picking');

Type guard

function isRefinementFree(schema): boolean {
  const checks = schema?._zod?.def?.checks;
  return !checks || checks.length === 0;
}

Try / catch

try {
  objSchema.pick({ a: true });
} catch (e) {
  if (e instanceof Error && e.message === '.pick() cannot be used on object schemas containing refinements') {
    // define the raw shape, pick from it, then re-attach the refinement to the result
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling `.pick({ a: true })` (or `.omit(...)`) on an object that was refined, e.g. `z.object({ a, b }).refine((v) => v.a === v.b).pick({ a: true })`.

Common situations: Building a partial/preview type from a validated domain object that has cross-field invariants; reusing a base schema with `.refine` for an update/patch shape.

Related errors


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