A stale schema is worse than no schema: it actively misleads consumers and downstream tooling. When openapi.yaml documents 8 endpoints but 12 exist in code, SDK generators produce incomplete clients, contract tests pass against a fiction, and third-party integrators build on fields that have already changed. iso-25010:2011 compatibility.interoperability fails in the most damaging way — the schema signals reliability it does not deliver. Drift compounds silently with every schema-less code change.
Critical because a drifted schema gives consumers false confidence, causes SDK generation failures, and makes contract tests useless as a regression guard.
Eliminate schema drift by generating the spec from code rather than maintaining it manually. Use Zod schemas as the single source of truth for both validation and OpenAPI output:
// Zod schema validates requests AND generates OpenAPI spec:
const UserSchema = z.object({
id: z.string().uuid(),
name: z.string(),
email: z.string().email(),
})
// Same object drives runtime validation and schema export
If you maintain the spec manually, add a CI step using openapi-diff or spectral that fails the build when the spec does not match the implementation. Run it on every pull request.
ID: api-design.contract-quality.schema-accuracy
Severity: critical
What to look for: If a schema definition exists, verify it matches the actual implementation. Compare: (1) endpoints listed in the schema vs. actual route definitions -- are there routes not in the spec, or spec entries with no implementation? (2) Request body schemas vs. what the handler actually validates/accepts. (3) Response schemas vs. what the handler actually returns. (4) Status codes documented vs. status codes actually returned. Look for staleness indicators: last-modified date of the spec file vs. recent route changes, schema referencing fields or endpoints that no longer exist.
Pass criteria: The schema accurately represents the current API. Count all implemented endpoints and count all endpoints in the schema. All implemented endpoints appear in the schema. Request/response shapes in the schema match what the handlers actually accept and return. No phantom endpoints (in spec but not implemented) or undocumented endpoints (implemented but not in spec). Report the count of matched vs unmatched endpoints even on pass.
Fail criteria: Schema is stale -- endpoints exist in code but not in the spec, or the spec documents fields/shapes that don't match the implementation. More than 20% of endpoints are missing from or inaccurate in the spec (e.g., 12 routes in code but only 8 in openapi.yaml).
Skip (N/A) when: No schema definition exists (covered by schema-exists check). This check only applies when a schema is present.
Detail on fail: Describe the drift (e.g., "OpenAPI spec lists 8 endpoints but 12 route handlers exist. /api/notifications and /api/webhooks are undocumented. User response schema shows role field but implementation returns roles array."). Max 500 chars.
Remediation: Keep your schema in sync with your implementation. The best approach is code-first generation -- derive the schema from your code so it cannot drift:
// Use Zod schemas for validation AND OpenAPI generation:
const UserSchema = z.object({
id: z.string().uuid(),
name: z.string(),
email: z.string().email(),
})
// Same schema validates requests AND generates OpenAPI spec
If maintaining a spec manually, add a CI check that compares the spec against the implementation (tools: openapi-diff, spectral).