schema_breaking_change
HTTP 409 · code: "schema_breaking_change" · type: https://docs.formfeed.dev/errors/schema-breaking-change
Publishing a version, moving a release channel, promoting its canary or rolling it back would put a version live whose stored data schema refuses data the current version accepts. The request changed nothing.
Example
{
"type": "https://docs.formfeed.dev/errors/schema-breaking-change",
"title": "Schema change breaks callers",
"status": 409,
"detail": "Publishing version 8 would break callers of the current version: \"customer.email\" is now required (and 1 more). Pass allow_breaking to go ahead",
"code": "schema_breaking_change",
"breaking": [
{
"path": "customer.email",
"pointer": "/properties/customer/properties/email",
"kind": "field-became-required",
"breaking": true,
"message": "\"customer.email\" is now required"
},
{
"path": "status",
"pointer": "/properties/status",
"kind": "enum-values-removed",
"breaking": true,
"message": "\"status\" no longer accepts \"draft\""
}
],
"safe": [],
"request_id": "req_4b7c1e9a2f3d4c5b8a6e7f9012"
}
| Field | Meaning |
|---|---|
breaking | Every breaking change, with the field path, a JSON pointer into the schema, its kind and a readable message |
safe | The changes that do not break callers, for the complete picture |
Common causes
POST /templates/{id}/versions/{number}/publishfor a version whose schema adds a required field, makes a field required, narrows a type or removes an enum value.POST /templates/{id}/versionswith"publish": trueand such a schema.PUT /templates/{id}/channels/{name}with a main or canary version like that, andpromoteorrollbackto one.formfeed templates push --publishor--channel, andformfeed channels set|promote|rollback; the CLI prints the changes and exits with code 1.
The check only refuses when both versions store a data schema. With an inferred schema on either side, the changes are reported in schema_check as a warning. What counts as breaking lists every rule.
How to fix it
- If callers would really break: change the schema so the new field is optional, or keep the old type or enum value, and create a new version.
- If every caller already sends what the new schema requires: repeat the request with
"allow_breaking": true(--allow-breakingin the CLI, Publish anyway in the editor,allowBreaking/allow_breakingin the SDKs). - Afterwards regenerate your types with
formfeed types, so your code sees the new schema. See Typed template data.
Retry?
No. Retrying the same request gives the same answer; change the schema or send allow_breaking first. If you send an Idempotency-Key with the POST, use a new one: a 4xx answer is stored under its key for 24 hours.