colinhacks/zod · error · Error

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

Error message

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

What it means

Thrown by `.omit()` when the target object schema has refinement checks attached (`.refine()`, `.superRefine()`, or similar) — see the `hasChecks` guard at util.ts:633-635. Refinements operate over the whole object, so dropping fields via `.omit()` would silently invalidate them; the library refuses rather than guess. The message points the user toward restructuring instead.

Source

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

        newShape[key] = currDef.shape[key]!;
      }

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

  return clone(schema, def) as any;
}

export function omit(schema: schemas.$ZodObject, mask: object): any {
  const currDef = schema._zod.def;

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

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

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

View on GitHub (pinned to 912f0f51b0)

Solutions

  1. Move the refinement onto a separate schema after `.omit()`: define the bare object, `omit` it, then attach `.refine()` to the result.
  2. Replace the refinement with per-field checks (`.refine()` on individual fields) so it survives `.omit()`.
  3. Use `.safeExtend()` or rebuild the shape manually instead of `.omit()` when you must preserve the refinement.

Example fix

// before
const User = z.object({ id: z.string(), email: z.string() }).refine(d => d.id !== d.email);
const NewUser = User.omit({ id: true }); // throws

// after
const Base = z.object({ id: z.string(), email: z.string() });
const NewUser = Base.omit({ id: true }).refine(d => d.id !== d.email);
Defensive patterns

Strategy: type-guard

Validate before calling

function hasRefinements(s: z.core.$ZodObject): boolean {
  return !!s._zod.def.checks?.length;
}
if (hasRefinements(User)) {
  // omit on a bare variant instead
}

Type guard

function isRefinementFree(s: z.core.$ZodObject): s is z.core.$ZodObject & { _zod: { def: { checks: [] } } } {
  return !s._zod.def.checks?.length;
}

Try / catch

try { const Out = User.omit({ id: true }); } catch (e) {
  if (e instanceof Error && /omit.*refinements/.test(e.message)) {
    const Out = Bare.omit({ id: true }).refine(/* original */);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling `Schema.omit({...})` on a schema built as `z.object({...}).refine(...)` or `z.object({...}).superRefine(...)`, or composing with any check that lands in `def.checks`.

Common situations: Building a create/update variant of a validated schema by omitting fields (e.g. `User.omit({ id: true })`) when `User` was defined with cross-field validation; refactoring validation into the base object; migrating from v3 patterns that allowed this.

Related errors


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