PATCH /core/v1/domains/{domainName} accepts any combination of
autorenewEnabled, privacyEnabled, and locked. The spec combines them with
anyOf, which means at least one, so a body carrying two or three is valid.
The SDK models that anyOf as an exclusive union. UpdateDomainRequestBody
holds three pointers and a private typ, and MarshalJSON returns on the first
non-nil variant:
func (u UpdateDomainRequestBody) MarshalJSON() ([]byte, error) {
if u.typ == "UpdateDomainRequestBodyAutorenewEnabled" || u.UpdateDomainRequestBodyAutorenewEnabled != nil {
return json.Marshal(u.UpdateDomainRequestBodyAutorenewEnabled)
}
if u.typ == "UpdateDomainRequestBodyPrivacyEnabled" || u.UpdateDomainRequestBodyPrivacyEnabled != nil {
return json.Marshal(u.UpdateDomainRequestBodyPrivacyEnabled)
}
if u.typ == "UpdateDomainRequestBodyLocked" || u.UpdateDomainRequestBodyLocked != nil {
return json.Marshal(u.UpdateDomainRequestBodyLocked)
}
return nil, fmt.Errorf("type %T does not include a non-empty union type", u)
}
Setting more than one field silently discards all but the first. There is no
error and no warning; the request succeeds.
Version: v1.33.3 · Go: 1.26.6
Reproduction
package main
import (
"encoding/json"
"fmt"
coreapigo "github.com/namedotcom/core-api-go"
)
func main() {
body := &coreapigo.UpdateDomainRequestBody{
UpdateDomainRequestBodyAutorenewEnabled: &coreapigo.UpdateDomainRequestBodyAutorenewEnabled{AutorenewEnabled: true},
UpdateDomainRequestBodyPrivacyEnabled: &coreapigo.UpdateDomainRequestBodyPrivacyEnabled{PrivacyEnabled: false},
UpdateDomainRequestBodyLocked: &coreapigo.UpdateDomainRequestBodyLocked{Locked: false},
}
b, err := json.Marshal(body)
fmt.Printf("all three set -> %s (err=%v)\n", b, err)
}
Actual
all three set -> {"autorenewEnabled":true} (err=<nil>)
Expected
all three set -> {"autorenewEnabled":true,"locked":false,"privacyEnabled":false} (err=<nil>)
Impact
locked is the transfer lock. A caller that sets it alongside another field —
which the API permits and which is the natural shape of a read-modify-write
update — gets a 200 and no change to the lock. The next thing that happens is
an outbound transfer that should have been blocked.
privacyEnabled is billable, and can be dropped the same way.
The failure mode is the one that is hardest to catch: the code reads correctly,
compiles, and passes any test that does not assert the bytes on the wire.
Suggested fix
Model the body as one object with three optional fields, matching the spec.
Over sibling properties, anyOf means "at least one of these", not "exactly one
of these" — the latter is oneOf. If the "at least one" constraint should be
enforced, validating it at the call site preserves the ability to send several.
It is worth checking whether other anyOf request bodies in this SDK are
modelled the same way. This one surfaced only because the operation happens to
be one where sending several fields together is the normal usage.
Note
.fernignore exempts only .fern/replay.lock, .fern/replay.yml, and
.gitattributes, so domains.go is regenerated. The durable fix is likely in
the API description or in the generator's anyOf handling rather than in a
patch to the Go source.
Workaround, for anyone who finds this first
Pass a nil Body and supply the fields through option.WithBodyProperties,
which the SDK marshals verbatim:
_, err := client.Domains.UpdateDomain(ctx,
&coreapigo.UpdateDomainRequest{DomainName: domain},
option.WithBodyProperties(map[string]any{
"autorenewEnabled": autorenew,
"privacyEnabled": privacy,
"locked": locked,
}))
PATCH /core/v1/domains/{domainName}accepts any combination ofautorenewEnabled,privacyEnabled, andlocked. The spec combines them withanyOf, which means at least one, so a body carrying two or three is valid.The SDK models that
anyOfas an exclusive union.UpdateDomainRequestBodyholds three pointers and a private
typ, andMarshalJSONreturns on the firstnon-nil variant:
Setting more than one field silently discards all but the first. There is no
error and no warning; the request succeeds.
Version: v1.33.3 · Go: 1.26.6
Reproduction
Actual
Expected
Impact
lockedis the transfer lock. A caller that sets it alongside another field —which the API permits and which is the natural shape of a read-modify-write
update — gets a
200and no change to the lock. The next thing that happens isan outbound transfer that should have been blocked.
privacyEnabledis billable, and can be dropped the same way.The failure mode is the one that is hardest to catch: the code reads correctly,
compiles, and passes any test that does not assert the bytes on the wire.
Suggested fix
Model the body as one object with three optional fields, matching the spec.
Over sibling properties,
anyOfmeans "at least one of these", not "exactly oneof these" — the latter is
oneOf. If the "at least one" constraint should beenforced, validating it at the call site preserves the ability to send several.
It is worth checking whether other
anyOfrequest bodies in this SDK aremodelled the same way. This one surfaced only because the operation happens to
be one where sending several fields together is the normal usage.
Note
.fernignoreexempts only.fern/replay.lock,.fern/replay.yml, and.gitattributes, sodomains.gois regenerated. The durable fix is likely inthe API description or in the generator's
anyOfhandling rather than in apatch to the Go source.
Workaround, for anyone who finds this first
Pass a nil
Bodyand supply the fields throughoption.WithBodyProperties,which the SDK marshals verbatim: