-
Notifications
You must be signed in to change notification settings - Fork 0
Troubleshooting
-
Pointer receiver, value registration.
func (r *CreateUser) RequestBody()requiresapp.RegisterRoute(&CreateUser{...}). A value registration fails the assertion and the route is passed through — silently, because "does not implementValidatableRoute" is indistinguishable from "deliberately unvalidated". -
RequestBody()returns nil. That means "accepts no body". -
The extension is not registered.
validation.WithValidation(nil).
validation: codec "application/xml" cannot reject unknown members.
Implement StrictCodec.UnmarshalStrict, or enable WithAllowUnknownFields().
Unknown-field rejection is on by default and every registered codec has to be
able to enforce it. Either implement UnmarshalStrict on the codec, or state
explicitly that unknown members are allowed. Both are legitimate; silently
decoding leniently while the configuration says otherwise is not.
The client is sending a field the schema does not declare. Check for a typo on either side.
If the extra field is intentional — an established client you cannot change —
validation.WithAllowUnknownFields(). Understand what you are giving up: the
next misspelled field will be dropped silently and the request will return 200.
It should not — the field name is taken from the decoder's JSON pointer
precisely so the response carries the client's own term rather than
api.CreateUserRequest. If you are constructing the error yourself, use
validation.UnknownFieldName(err) rather than err.Error().
The Content-Type header does not match a registered codec. Check for:
- a missing header entirely — some clients omit it on POST
-
text/jsonorapplication/json5rather thanapplication/json - a codec you meant to register and did not
The client's Accept header matches no registered codec. Accept: */* or an
absent header uses the first registered codec, so this only happens when the
client asked for something specific.
Two cases:
- The route declares no schemas. Then there is no negotiated codec and the handler's own write goes out as-is.
-
It is an error response. Problem documents deliberately ignore
Acceptand are alwaysapplication/problem+json.
That is strict mode doing its job: the handler wrote a status not listed in
Responses(). The log names which.
Document every status your handlers can produce, including error paths.
rextension.Problem is the schema for all of them — see
Response Validation for a helper that makes that terse.
Response validation buffers and re-decodes the body, which is wrong for server-sent events, long polling or a file download.
Return nil from Responses() on those routes — the route is then passed
through untouched.
⚠ Wire break. The 422 is now an RFC 9457 problem document served as
application/problem+json:
// before {"status":422,"message":"Validation failed", "errors":[{"field":"email","tag":"email","message":"..."}]} // after {"type":"urn:rex:problem:validation-failed","title":"Unprocessable Entity", "status":422,"detail":"the request body failed validation", "errors":[{"field":"email","rule":"email","message":"..."}]}
tag became rule — "tag" named the Go struct tag that produced the constraint
rather than the constraint itself. validation.ValidationErrorResponse still
resolves as a name; it is now an alias of rextension.Problem, so it does not
keep the old shape.
The type parameter does not match the type in the schema:
func (r *CreateUser) RequestBody() validation.BodySchema { return validation.Scalar(CreateUserRequest{}) } body, ok := validation.GetRequestBody[CreateUserRequest](r) // ← must match
It also returns false when the route declares no request schema, or when validation did not run.
Nested structs validate automatically, but slices and maps need dive:
Tags []string `json:"tags" validate:"max=10,dive,min=1"`
Without dive, min=1 applies to the slice length rather than to each element.
It does not — validation is PriorityValidation (500) and authentication is
PriorityAuth (400), so a body is never parsed for a request that was going to
be refused. If you are seeing the opposite, something registered the validation
middleware at a lower priority by hand.