Skip to content

docs: the migration guide promised silence where v3 now returns 422 - #182

Merged
raspbeguy merged 1 commit into
mainfrom
docs/close-two-gaps
Aug 13, 2026
Merged

docs: the migration guide promised silence where v3 now returns 422#182
raspbeguy merged 1 commit into
mainfrom
docs/close-two-gaps

Conversation

@raspbeguy

Copy link
Copy Markdown
Member

Two doc gaps, one of which was worse than a gap.

The migration guide gave advice that rc3 reversed

docs/migration-v2-to-v3.md carried a section titled "Removed request fields are ignored, not rejected", telling an upgrading operator that a stale mac or mac_aliases would be dropped in silence and answer 200. rc3's unknown-field rejection inverted exactly that. A migration guide is the one document where being wrong costs someone an outage, so this was not a missing paragraph but a misleading one.

Measured against the installed rc3, the section was wrong on two of its four claims:

PATCH dhcp/hosts {"mac": ...}                      doc said 200, ignored   ->  422
POST network/interfaces {"name": ...}              doc said 200 + generated id  ->  422
PATCH dhcp/hosts {"managed": false}                doc said ignored        ->  200, still correct
PATCH network/interfaces {"ipaddr": ...}           doc said the exception  ->  200, still correct

The rewrite says what happens now, and the news is good: the silent-failure hazard the section warned about is gone. Both quoted error bodies are copied from a device rather than composed:

{ "code": "validation_failed", ..., "errors": [ { "field": "mac", "code": "unknown_field",
  "message": "no such field \"mac\" on this resource" } ] }

The network/interfaces.name case flips from the guide's "sharpest silent case" to a loud failure, which is the outcome an IaC client wants: in v2 it created an interface under a generated name that the client then read as drift and duplicated.

It also now states the part that is easy to get wrong in the other direction. id, managed and runtime stay accepted and ignored because every apply is a read-modify-write, and a readOnly field that still exists in the model behaves the same way, which is why ipaddr is accepted rather than refused. Only names the resource does not model at all are rejected. Verified on a device, including that a full read PUT back returns 200 and that swapping name for id makes the create succeed.

versioning.md overstated what the clear-on-omit flag restricts

It read as though explicit JSON null were only accepted for fields carrying x-uapi-clear-on-omit. The server accepts null for any modeled field and clears the option, flagged or not, which is what makes a read-modify-write work when the read answered null. The flag marks where clearing is safe, not where it is possible, and its real value is that a defaulted field is never marked, so a client honouring the flag cannot enter the non-converging diff loop the same paragraph describes.

Does this change the wire surface? No. Documentation only; both passages now describe behaviour that already shipped in rc3.

Was it verified against a real device, or only by CI? On the device running rc3 from the published APK. Every status code and both error bodies in the rewritten section were taken from it. make lint, which includes lint-doc-refs, and 1230 unit tests pass.

Was LuCI checked? Not applicable. No uci semantics are involved.

@raspbeguy
raspbeguy force-pushed the docs/close-two-gaps branch from a09df59 to 907e6d9 Compare August 13, 2026 13:02
@raspbeguy
raspbeguy merged commit c57c9fa into main Aug 13, 2026
6 checks passed
@raspbeguy
raspbeguy deleted the docs/close-two-gaps branch August 13, 2026 13:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant