On this page
How to read this list
Every entry uses the same example orders API. The snippet shows the part of the spec that changed, before and after, as two YAML documents. The caption names the rule oasdiff reported when we ran the full before and after specs through oasdiff 1.34.1 on 2026-11-09, and its level:
- error: a definite breaking change. oasdiff’s test is whether “a consumer that followed the old contract can stop working under the new one”.
- warning: may break, but the spec does not say enough to decide.
- info: not breaking.
oasdiff has hundreds of checks; this page covers the ones most pull requests hit. The full catalogue is on oasdiff’s breaking-changes reference, and oasdiff checks changelog prints it for the version you have installed.
oasdiff breaking base.yaml revision.yaml
oasdiff changelog base.yaml revision.yaml
# Compare with the spec on main, straight from git
oasdiff changelog main:openapi.yaml openapi.yamlbreaking shows errors and warnings; changelog shows every level.Quick reference
| Change | oasdiff rule | oasdiff level | Graphwake by default |
|---|---|---|---|
| Remove an endpoint | api-removed-without-deprecation | error | Alert |
| Remove an endpoint that was deprecated | api-removed-with-deprecation | info | Alert |
| Remove a required response field | response-required-property-removed | error | Alert |
| Remove an optional response field | response-optional-property-removed | info | Alert |
| Change a response field’s type | response-property-type-changed | error | Alert |
| A response field becomes optional | response-property-became-optional | error | Alert |
| Add an enum value to a response field | response-property-enum-value-added | error | Alert |
| Remove a success status | response-success-status-removed | error | Alert |
| Add a required parameter | new-required-request-parameter | error | Alert |
| A parameter becomes required | request-parameter-became-required | error | Alert |
| Add a required request field | new-required-request-property | error | Alert |
| A request field becomes required | request-property-became-required | error | Alert |
| Change a request field’s type | request-property-type-changed | error | Alert |
| Remove an accepted enum value | request-property-enum-value-removed | error | Alert |
| Lower a request field’s maxLength | request-property-max-length-decreased | error | Alert |
| Remove a query parameter | request-parameter-removed | warning | Quiet unless the team opts in |
| Remove a request field | request-property-removed | warning | Quiet unless the team opts in |
| Add an endpoint | endpoint-added | info | Quiet unless the team opts in |
| Add an optional parameter | new-optional-request-parameter | info | Quiet unless the team opts in |
| Add an optional request field | new-optional-request-property | info | Quiet unless the team opts in |
| Add a response field | response-optional-property-added | info | Quiet unless the team opts in |
| Accept a new enum value | request-property-enum-value-added | info | Quiet unless the team opts in |
| Raise a request field’s maxLength | request-property-max-length-increased | info | Quiet unless the team opts in |
| A request field becomes optional | request-property-became-optional | info | Quiet unless the team opts in |
| Remove an enum value from a response field | response-property-enum-value-removed | info | Quiet unless the team opts in |
“Alert” means Graphwake tells the teams subscribed to that endpoint. The two rows where Graphwake alerts on an oasdiff info are explained under where tools disagree.
What Graphwake counts as breaking
Graphwake counts these as breaking, among others: removed endpoints, removed or retyped response fields, response fields that become optional, new response enum values, removed success statuses, new or newly required parameters and request fields, retyped request fields, and narrower accepted values. It also always alerts on removed response fields and removed endpoints, including the two cases under where tools disagree. Changes that cannot break a client stay quiet unless a team opts in.
Only the teams that use it
Consumer teams subscribe to the endpoints they call. A breaking change alerts those teams, in Slack, Microsoft Teams or email.
Removals always alert
A removed endpoint or response field breaks a caller, deprecated or not, optional or not. Graphwake alerts on every one.
Quiet by default
Non-breaking changes do not alert anyone. A team can opt in to every change on the endpoints it uses.
Impact before the merge
Each change set gets a 0-100 impact score from the breaking changes, the teams and people they reach, and blind spots.
Breaking changes in responses
A client reads the response. Anything it relied on that disappears, changes shape or takes a value the client has never seen can make it fail.
Remove an endpoint
Every call to it now gets a 404 or 405. This is the most visible break and the easiest to miss in review when the operation sits in a long file.
# Before
/orders:
get:
responses:
"200":
description: Orders
post:
responses:
"201":
description: Created
---
# After
/orders:
get:
responses:
"200":
description: Orders/orders path item (a Paths Object). POST /orders is gone. oasdiff: api-removed-without-deprecation (error).Remove a required response field
A client that reads total gets nothing. Depending on the language, that is a crash, a null shown to a user or a wrong sum.
# Before
type: object
required: [id, total]
properties:
id:
type: string
total:
type: number
---
# After
type: object
required: [id]
properties:
id:
type: string
GET /orders/{id}, 200 response schema (a Schema Object). oasdiff: response-required-property-removed (error).Change a response field’s type
A client that parses total as a number fails on a string, even when the string holds the same digits.
# Before
type: object
required: [id, total]
properties:
id:
type: string
total:
type: number
---
# After
type: object
required: [id, total]
properties:
id:
type: string
total:
type: string
GET /orders/{id}, 200 response schema (a Schema Object). oasdiff: response-property-type-changed (error).A response field becomes optional
The field is still there today, but the spec no longer promises it. Clients that assumed it is always present have to handle its absence.
# Before
type: object
required: [id, total]
properties:
id:
type: string
total:
type: number
---
# After
type: object
required: [id]
properties:
id:
type: string
total:
type: number
GET /orders/{id}, 200 response schema (a Schema Object). oasdiff: response-property-became-optional (error).Add an enum value to a response field
This one surprises people: it is an addition, and oasdiff still calls it breaking. A client with an exhaustive switch over status has no branch for refunded. See where tools disagree.
# Before
properties:
status:
type: string
enum: [paid, shipped]
---
# After
properties:
status:
type: string
enum: [paid, shipped, refunded]GET /orders/{id}, 200 response schema (a Schema Object). oasdiff: response-property-enum-value-added (error).Remove a success status
Moving from 200 to 201 looks cosmetic. A client that checks for exactly 200 now treats every success as a failure.
# Before
"200":
description: Created
---
# After
"201":
description: CreatedPOST /orders responses (a Responses Object). oasdiff: response-success-status-removed (error).Breaking changes in requests
A client sends the request. Anything that turns a request that was valid yesterday into an invalid one is breaking, whether or not your server would still accept it today.
Add a required parameter
Every existing caller omits status, so every existing call is now invalid.
# Before
- name: limit
in: query
schema:
type: integer
---
# After
- name: limit
in: query
schema:
type: integer
- name: status
in: query
required: true
schema:
type: stringGET /orders parameters (a list of Parameter Objects). oasdiff: new-required-request-parameter (error).A parameter becomes required
Same effect as adding one: callers that left it out now send an invalid request.
# Before
- name: status
in: query
required: false
schema:
type: string
---
# After
- name: status
in: query
required: true
schema:
type: stringGET /orders parameters (a list of Parameter Objects). oasdiff: request-parameter-became-required (error).Add a required request field
Existing clients do not send currency. If the server enforces the schema, they get a 400.
# Before
type: object
required: [items]
properties:
items:
type: array
items:
type: string
---
# After
type: object
required: [items, currency]
properties:
items:
type: array
items:
type: string
currency:
type: string
POST /orders request body schema (a Schema Object). oasdiff: new-required-request-property (error).A request field becomes required
Clients that treated coupon as optional and left it out now send invalid bodies.
# Before
type: object
required: [items]
properties:
items:
type: array
items:
type: string
coupon:
type: string
---
# After
type: object
required: [items, coupon]
properties:
items:
type: array
items:
type: string
coupon:
type: string
POST /orders request body schema (a Schema Object). oasdiff: request-property-became-required (error).Change a request field’s type
Clients send quantity as a number; the spec now wants a string.
# Before
type: object
required: [items]
properties:
items:
type: array
items:
type: string
quantity:
type: integer
---
# After
type: object
required: [items]
properties:
items:
type: array
items:
type: string
quantity:
type: string
POST /orders request body schema (a Schema Object). oasdiff: request-property-type-changed (error).Remove an accepted enum value
A client that sends GBP is now outside the contract.
# Before
type: object
required: [items]
properties:
items:
type: array
items:
type: string
currency:
type: string
enum: [EUR, USD, GBP]
---
# After
type: object
required: [items]
properties:
items:
type: array
items:
type: string
currency:
type: string
enum: [EUR, USD]
POST /orders request body schema (a Schema Object). oasdiff: request-property-enum-value-removed (error).Lower a request field’s maxLength
A 20-character coupon code was valid; now it is not. Any narrowed constraint (a lower maximum, a higher minimum, a stricter pattern) works the same way.
# Before
type: object
required: [items]
properties:
items:
type: array
items:
type: string
coupon:
type: string
maxLength: 64
---
# After
type: object
required: [items]
properties:
items:
type: array
items:
type: string
coupon:
type: string
maxLength: 16
POST /orders request body schema (a Schema Object). oasdiff: request-property-max-length-decreased (error).It depends: warnings
oasdiff reports these as warnings. Old clients keep sending the value; most servers ignore what they no longer read, but a server that rejects unknown fields or parameters will now fail those calls. Check how your server treats extra input before you decide.
Remove a query parameter
Callers still send status. Whether that breaks depends on the server.
# Before
- name: limit
in: query
schema:
type: integer
- name: status
in: query
required: false
schema:
type: string
---
# After
- name: limit
in: query
schema:
type: integerGET /orders parameters (a list of Parameter Objects). oasdiff: request-parameter-removed (warning).Remove a request field
Callers still send coupon. With additionalProperties: false or strict validation on the server, that request now fails.
# Before
type: object
required: [items]
properties:
items:
type: array
items:
type: string
coupon:
type: string
---
# After
type: object
required: [items]
properties:
items:
type: array
items:
type: string
POST /orders request body schema (a Schema Object). oasdiff: request-property-removed (warning).Not breaking
Additions and relaxed rules. A client built against the old spec keeps working, provided it ignores response fields it does not know, which most JSON clients do by default.
Add an endpoint
Nobody calls it yet, so nobody can break.
# Before
/orders:
get:
responses:
"200":
description: Orders
---
# After
/orders:
get:
responses:
"200":
description: Orders
/orders/{id}/receipt:
get:
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: The receiptGET /orders/{id}/receipt is new. oasdiff: endpoint-added (info).Add an optional parameter
Existing calls leave it out, which is allowed.
# Before
- name: limit
in: query
schema:
type: integer
---
# After
- name: limit
in: query
schema:
type: integer
- name: status
in: query
required: false
schema:
type: stringGET /orders parameters (a list of Parameter Objects). oasdiff: new-optional-request-parameter (info).Add an optional request field
Existing bodies without coupon stay valid.
# Before
type: object
required: [items]
properties:
items:
type: array
items:
type: string
---
# After
type: object
required: [items]
properties:
items:
type: array
items:
type: string
coupon:
type: string
POST /orders request body schema (a Schema Object). oasdiff: new-optional-request-property (info).Add a response field
Clients that ignore unknown fields see no difference. A client that rejects unknown fields (a strict deserializer) does, so know your clients.
# Before
type: object
required: [id, total]
properties:
id:
type: string
total:
type: number
---
# After
type: object
required: [id, total]
properties:
id:
type: string
total:
type: number
note:
type: string
GET /orders/{id}, 200 response schema (a Schema Object). oasdiff: response-optional-property-added (info).Accept a new enum value
Clients keep sending the values they already send.
# Before
type: object
required: [items]
properties:
items:
type: array
items:
type: string
currency:
type: string
enum: [EUR, USD]
---
# After
type: object
required: [items]
properties:
items:
type: array
items:
type: string
currency:
type: string
enum: [EUR, USD, GBP]
POST /orders request body schema (a Schema Object). oasdiff: request-property-enum-value-added (info).Raise a request field’s maxLength
Every value that was valid is still valid. The same goes for any loosened constraint.
# Before
type: object
required: [items]
properties:
items:
type: array
items:
type: string
coupon:
type: string
maxLength: 16
---
# After
type: object
required: [items]
properties:
items:
type: array
items:
type: string
coupon:
type: string
maxLength: 64
POST /orders request body schema (a Schema Object). oasdiff: request-property-max-length-increased (info).A request field becomes optional
Clients that send it can keep sending it.
# Before
type: object
required: [items, currency]
properties:
items:
type: array
items:
type: string
currency:
type: string
---
# After
type: object
required: [items]
properties:
items:
type: array
items:
type: string
currency:
type: string
POST /orders request body schema (a Schema Object). oasdiff: request-property-became-optional (info).Remove an enum value from a response field
The client stops receiving a value it already handled. Its code for that value goes unused, but nothing fails.
# Before
properties:
status:
type: string
enum: [paid, shipped, refunded]
---
# After
properties:
status:
type: string
enum: [paid, shipped]GET /orders/{id}, 200 response schema (a Schema Object). oasdiff: response-property-enum-value-removed (info).Where tools disagree
Most of this list is not controversial. Three cases are, and it is worth deciding them on purpose instead of by tool default.
Adding an enum value to a response field
oasdiff calls it breaking (response-property-enum-value-added, shown above). GitHub’s Octokit guidance lists adding enum string constants as non-breaking. If your clients are written to handle unknown values, oasdiff supports marking the field with x-extensible-enum, which allows new values in responses.
Removing an optional response field
oasdiff reports it as info: an optional field may be absent anyway, so a correct client already copes. In practice clients read the optional fields they see. Graphwake treats removing any response field as breaking and alerts.
# Before
type: object
required: [id, total]
properties:
id:
type: string
total:
type: number
note:
type: string
---
# After
type: object
required: [id, total]
properties:
id:
type: string
total:
type: number
GET /orders/{id}, 200 response schema (a Schema Object). oasdiff: response-optional-property-removed (info).Removing an endpoint after deprecating it
oasdiff reports it as info, because the removal was announced. Every caller that has not moved yet still breaks, so Graphwake alerts on any removed endpoint.
# Before
/orders:
get:
responses:
"200":
description: Orders
post:
deprecated: true
responses:
"201":
description: Created
---
# After
/orders:
get:
responses:
"200":
description: Orders/orders path item (a Paths Object). POST /orders was deprecated, then removed. oasdiff: api-removed-with-deprecation (info).If your team draws the line differently, oasdiff lets you change the level of any check with --severity-levels and a file of rule IDs and levels.
When oasdiff alone is enough
- Every consumer of the API is in the same repository or team, so the diff in the pull request reaches everyone who needs it.
- You want a hard stop in CI:
oasdiff breaking --fail-on ERRexits non-zero on a breaking change. - You want to tune or extend the rules yourself.
Next steps
- Detect it, then decide who to tell: API breaking change alerts.
- Compare the two tools: oasdiff vs Graphwake.
- Review a spec change before it merges: the API breaking change checklist for pull requests.
- How the impact score weighs a change set.
Questions
What is a breaking change in OpenAPI?
A change to the spec after which a client built against the old version can fail: removing an endpoint or response field, adding a required parameter or request field, changing a type, or narrowing the values a request may contain.
Is adding a field a breaking change?
Adding an optional request field or a response field is not. Adding a required request field is, because existing clients do not send it.
Is adding an enum value a breaking change?
In a request, no: clients keep sending the values they know. In a response, oasdiff says yes, because a client may not handle the new value. Teams whose clients tolerate unknown values often treat it as safe.
How do I detect OpenAPI breaking changes automatically?
Run oasdiff on the old and new spec, for example oasdiff breaking base.yaml revision.yaml, locally or in CI. It is free and open source. Graphwake’s CI step checks the spec on every pull request, and Graphwake alerts the teams that consume each changed endpoint.
Does Graphwake alert on non-breaking changes?
Not by default. Only breaking changes alert. A team can opt in to every change on the endpoints it subscribes to.
Pick an endpoint. See who it reaches. 7-day free trial. Cancel before day 7 and you pay nothing.
Start free trialSources and last verified
- oasdiff.com/docs/breaking-changes
- github.com/oasdiff/oasdiff/blob/main/docs/BREAKING-CHANGES.md
- github.com/octokit/.github/blob/master/community/breaking_changes.md
- oasdiff and its name belong to its authors. Graphwake is not affiliated with the oasdiff project.
Sources checked on 2026-11-09.