Two validation libraries produce two schema syntaxes, two inferred-type systems, two error-object shapes, and two ways to compose refinements. A backend route validated with Zod cannot share its schema with a frontend form validated by Yup, so every endpoint has its contract defined twice and they drift the moment someone adds a field to only one side. Error rendering components branch on library-specific shapes, and TypeScript type narrowing works on one side but not the other.
High because schema drift between frontend and backend causes silent validation gaps where invalid data passes one check and fails the other.
Standardize on one library — Zod if you want TypeScript-first inference, Yup if you have deep Formik-era code. Colocate every schema in src/lib/schemas/ and import from both client and server code.
// src/lib/schemas/login.ts
import { z } from 'zod'
export const LoginSchema = z.object({
email: z.string().email(),
password: z.string().min(8),
})
export type LoginInput = z.infer<typeof LoginSchema>
Remove the loser with npm uninstall yup @hookform/resolvers.
ID: ai-slop-code-drift.tooling-stack-drift.dual-validation-library
Severity: high
What to look for: Apply the three-condition rule against this exact validation library allowlist: zod, yup, joi, valibot, superstruct, class-validator, io-ts, runtypes, arktype, @sinclair/typebox. Count all that meet all three conditions (at least 1 non-escape-hatch importing file). EXCEPT: if a validation library is a transitive peer dependency of a form library (e.g., yup shipping with @hookform/resolvers/yup) AND is imported in ≤2 files, treat it as an escape hatch.
Pass criteria: 0 or 1 validation libraries from the allowlist actively used. Report even on pass: "Canonical validation library: [name] ([N] importing files)."
Fail criteria: 2 or more validation libraries from the allowlist meet all three conditions (at least 1 non-escape-hatch importing file).
Skip (N/A) when: 0 validation libraries from the allowlist appear in RUNTIME_DEPS.
Detail on fail: "2 active validation libraries: 'zod' (18 files) AND 'yup' (7 files). Pick one — schemas should be consistent across the codebase."
Remediation: Two validation libraries means two schema syntaxes, two sets of types to maintain, two error formats. Pick one and migrate:
// Bad: src/lib/schemas.ts uses zod, src/forms/login.ts uses yup
// Good: every schema in zod (or every schema in yup), nothing in between
// src/lib/schemas.ts
import { z } from 'zod'
export const LoginSchema = z.object({ ... })