fix(clients): tolerate orphan client_inbounds rows in Delete

DeleteByEmail's previous fix only covered the case where GetRecordByEmail
returned ErrRecordNotFound. When the ClientRecord exists but a client_inbounds
row points to an inbound that has been removed out-of-band (failed mid-delete,
manual SQL, pre-SyncInbound migration), Delete bubbled the raw gorm
"record not found" from inboundSvc.GetInbound and aborted before any cleanup
ran — leaving the client un-deletable through the UI/API.

Match the tolerance bulkDelInboundClients already has: when GetInbound
returns gorm.ErrRecordNotFound for a join row, log a warning and continue.
The unconditional Delete(&model.ClientInbound{}) later in the function then
removes the stale row, and the ClientRecord delete succeeds.
This commit is contained in:
MHSanaei 2026-05-27 21:01:40 +02:00
parent 16b4ca0c26
commit 66b80fb81b
No known key found for this signature in database
GPG key ID: 7E4060F2FBE5AB7A

View file

@ -678,6 +678,10 @@ func (s *ClientService) Delete(inboundSvc *InboundService, id int, keepTraffic b
for _, ibId := range inboundIds { for _, ibId := range inboundIds {
inbound, getErr := inboundSvc.GetInbound(ibId) inbound, getErr := inboundSvc.GetInbound(ibId)
if getErr != nil { if getErr != nil {
if errors.Is(getErr, gorm.ErrRecordNotFound) {
logger.Warningf("Delete: skipping orphan client_inbounds row for client_id=%d, inbound_id=%d (inbound missing)", id, ibId)
continue
}
return needRestart, getErr return needRestart, getErr
} }
key := clientKeyForProtocol(inbound.Protocol, existing) key := clientKeyForProtocol(inbound.Protocol, existing)