fix(api/v2): map ValidationHTTPError to its HTTP status

translateDomainError only recognized web.HTTPErrorProcessor, so a
ValidationHTTPError from InvalidFieldError (e.g. an unknown webhook
event) leaked as a 500 instead of the 412 v1 returns. It carries the
status via GetHTTPCode() but cannot implement HTTPErrorProcessor because
the embedded web.HTTPError field shadows the method name. Add a
GetHTTPCode/GetCode branch so v2 surfaces the right status and preserves
the v1 numeric code on the body.
This commit is contained in:
kolaente 2026-06-05 10:13:21 +02:00 committed by kolaente
parent 43bbeed1c8
commit d76c009808
2 changed files with 33 additions and 0 deletions

View File

@ -131,6 +131,13 @@ func (err ValidationHTTPError) GetHTTPCode() int {
return err.HTTPCode
}
// GetCode returns Vikunja's numeric domain error code. v2's translateDomainError
// reads it to keep the v1 `code` body contract, since this type does not
// implement web.HTTPErrorProcessor (the embedded field shadows the method name).
func (err ValidationHTTPError) GetCode() int {
return err.Code
}
func InvalidFieldError(fields []string) error {
return InvalidFieldErrorWithMessage(fields, "Invalid Data")
}

View File

@ -43,6 +43,21 @@ func authFromCtx(ctx context.Context) (web.Auth, error) {
return a, nil
}
// httpCodeGetter is satisfied by validation errors that carry an HTTP status
// without the HTTPErrorProcessor method — notably models.ValidationHTTPError,
// returned by InvalidFieldError. v1's error handler reads GetHTTPCode() off these;
// without the same branch here they'd fall through to a 500.
type httpCodeGetter interface {
GetHTTPCode() int
}
// domainCodeGetter exposes Vikunja's numeric domain error code on errors that
// are not HTTPErrorProcessors (again, ValidationHTTPError) so v2 can keep the v1
// `code` body contract.
type domainCodeGetter interface {
GetCode() int
}
// translateDomainError maps a Vikunja domain error (web.HTTPErrorProcessor)
// onto Huma's status-error type so the response carries the right code
// and an RFC 9457 body. Errors without HTTP semantics fall through, which
@ -67,6 +82,17 @@ func translateDomainError(err error) error {
}
return se
}
var cg httpCodeGetter
if errors.As(err, &cg) {
se := huma.NewError(cg.GetHTTPCode(), err.Error())
if vm, ok := se.(*vikunjaErrorModel); ok {
var dc domainCodeGetter
if errors.As(err, &dc) {
vm.Code = dc.GetCode()
}
}
return se
}
return err
}