package apiv1 import ( "errors" "github.com/danielgtaylor/huma/v2" "github.com/juanfont/headscale/hscontrol/db" "github.com/juanfont/headscale/hscontrol/state" "github.com/juanfont/headscale/hscontrol/types" "github.com/juanfont/headscale/hscontrol/util" "gorm.io/gorm" ) // mapError translates a state/db-layer error into a Huma HTTP error // (NotFound→404, invalid input→400, conflict→409, everything else→500). // Handlers use this default mapping and may return a more specific huma.ErrorN // directly. msg is a human context prefix, e.g. "getting node". func mapError(msg string, err error) error { if err == nil { return nil } switch { case errors.Is(err, types.ErrRegistrationPayloadTooLarge): return huma.Error413RequestEntityTooLarge(msg, err) case errors.Is(err, state.ErrAuthCacheFull), errors.Is(err, state.ErrAuthCacheClosed): return huma.Error503ServiceUnavailable(msg, err) case errors.Is(err, gorm.ErrRecordNotFound), errors.Is(err, state.ErrNodeNotFound), errors.Is(err, state.ErrNodeNotInNodeStore), errors.Is(err, db.ErrUserNotFound), errors.Is(err, db.ErrNodeNotFoundRegistrationCache), errors.Is(err, state.ErrRegistrationExpired): return huma.Error404NotFound(msg, err) case errors.Is(err, state.ErrGivenNameInvalid), errors.Is(err, state.ErrGivenNameTaken), errors.Is(err, state.ErrNodeNameNotUnique), errors.Is(err, state.ErrNodeMarkedTaggedButHasNoTags), errors.Is(err, state.ErrNodeHasNeitherUserNorTags), errors.Is(err, state.ErrRequestedTagsInvalidOrNotPermitted), errors.Is(err, types.ErrExpiryOutOfRange), errors.Is(err, types.ErrHostinfoTooLarge), errors.Is(err, db.ErrUserStillHasNodes), errors.Is(err, db.ErrCannotChangeOIDCUser), errors.Is(err, util.ErrUsernameTooShort), errors.Is(err, util.ErrUsernameMustStartLetter), errors.Is(err, util.ErrUsernameTooManyAt), errors.Is(err, util.ErrUsernameInvalidChar), errors.Is(err, db.ErrPreAuthKeyNotTaggedOrOwned), errors.Is(err, db.ErrSingleUseAuthKeyHasBeenUsed), errors.Is(err, state.ErrInvalidPolicy): return huma.Error400BadRequest(msg, err) case errors.Is(err, state.ErrNodeKeyInUse), errors.Is(err, state.ErrAmbiguousNodeOwnership), errors.Is(err, state.ErrAuthCacheEntryExists): return huma.Error409Conflict(msg, err) default: return huma.Error500InternalServerError(msg, err) } }