fix(gen): emit omitzero for optional object request fields#27
Merged
Conversation
stdlib encoding/json's `,omitempty` never drops a bare struct value (only
false/0/""/nil-slice/nil-map/nil-pointer count as "empty"), so every
optional object-typed request field was always sent on the wire as `{}`.
For CreateSilenceRuleRequest.TimeFilter this made creating a
recurring-only silence rule impossible: the server's binding validates
StartTime/EndTime with `gt=0` whenever "time_filter" is present at all.
Emit `,omitzero` (Go 1.24+) instead of `,omitempty` in the json tag for
request fields that resolve to a generated struct type, leaving the
mirrored `toon` tag on `,omitempty` (toon-go only recognizes that
literal option) and all slice/map/scalar/pointer field handling
untouched. Regenerated models_gen.go: 50 fields affected, json-tag-only
diff.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Root cause
The generator emitted every optional request field with
json:"...,omitempty". stdlibencoding/json'somitemptynever drops a bare struct value (only false/0/""/nil slice/map/pointer count as "empty"), so every optional object-typed request field was always transmitted as{}.Confirmed production impact (AI-SRE audit 2026-07-09, session
sess_6fnryva2E5uPEtMwJWKvEw):CreateSilenceRuleRequest.TimeFilteralways rode the wire as"time_filter":{}, and the server binding validatesStartTime/EndTimewithgt=0whenevertime_filteris present — making a recurring-only silence rule (time_filtersonly) impossible via this SDK and everything built on it (fduty CLI). Six create attempts in one prod session all failed withStartTime must be greater than 0, EndTime must be greater than 0; combining both fields fails "cannot configure both".Fix
internal/cmd/gen: for request-context fields whose schema resolves (through$ref/allOf, mirroringemitModels' classifier) to a generated struct type, emitjson:"...,omitzero"(Go 1.24 stdlib; go.mod already declares go 1.24). Everything else keepsomitemptyexactly as before; the mirroredtoontag staysomitempty(toon-go only recognizes that literal option). No pointer-wrapping — zero call-site breakage.Regenerated
models_gen.go: 50 fields, strictly json-tag-only diff (verified: no other hunk kinds), includingCreate/UpdateSilenceRuleRequest.TimeFilter. Regeneration is idempotent against the committed generator.Verification
go build ./...,go vet ./...,go test ./... -count=1green.TestOptionalObjectRequestFieldOmitsWhenUnsetexercises the realnewRequestmarshal path: unsetTimeFilterproduces notime_filterkey; setTimeFilterkeeps it. Hand-reverting the tag toomitemptyreproduces the exact prod symptom ("time_filter":{}on the wire) and fails the test.flashduty.gojson.Marshal) is unconditionally stdlib; checked in-org importers (flashduty-cli, flashduty-mcp-server, terraform-provider) — none marshal these structs via jsoniter.Follow-up (not in this PR)
flashduty-cli needs a go-flashduty bump + release after this merges so prod runners pick up the fix.