Most contract tests were written to protect the happy path. Teams assert that a 200 body still has id, created_at and amount, because that is the payload the UI renders and the payload that breaks visibly when it changes. Error responses get a fraction of that attention, even though client code often branches on them more aggressively than on success bodies.
The gap is real across the industry. The SmartRecruiters API documentation lists "Status Code & Error Changes" as a category of breaking change: altering the HTTP status for an existing scenario, changing the structure of error responses, changing error codes and their meanings, or removing codes clients might rely on according to their breaking changes policy. The same page classifies additive changes (new optional fields, new enum values) as non-breaking, which is why an error payload can grow a new member with no warning while an existing member quietly changes meaning.
Contract testing tools can only judge what they are given. The Swagger contract testing documentation is explicit that "Contract Testing can only decide based on the information it receives. If the consumer contract does not contain all the interactions the consumer uses, then the resulting checks may say it is safe to deploy when it could not be" in the compatibility checks guide. If your consumer contract records only success interactions, the vendor's compatibility checker will happily pass a release that renamed card_declined to payment_declined.
There is a second layer of risk that schema testing does not reach at all. A schema test asserts that one system is compatible with a schema at a point in time, while a contract test asserts that two systems can actually communicate on agreed interactions as described in Pactflow's comparison. Error semantics are exactly the kind of thing that a valid schema will not catch: a 409 that becomes a 500 with the same documented envelope still validates against the schema, and still breaks your code.



