From 9e61e5e1b737019e444b141c13fa7cd49b2be227 Mon Sep 17 00:00:00 2001 From: Sacha Al Himdani Date: Wed, 29 Apr 2026 14:12:58 +0200 Subject: [PATCH] Return clear error on user delete FK violation Deleting a membership profile referenced by other tables (owner, approver, assignee, etc.) surfaced as a generic Internal error. Detect the Postgres FK violation (23503) in the coredata Delete, return ErrResourceInUse, and map it to CONFLICT in the GraphQL and MCP resolvers so the client sees an actionable error. Signed-off-by: Sacha Al Himdani --- pkg/coredata/membership_profile.go | 5 +++++ pkg/server/api/connect/v1/profile_resolvers.go | 4 ++++ pkg/server/api/mcp/v1/schema.resolvers.go | 3 +++ 3 files changed, 12 insertions(+) diff --git a/pkg/coredata/membership_profile.go b/pkg/coredata/membership_profile.go index 0745368d5..e478704a3 100644 --- a/pkg/coredata/membership_profile.go +++ b/pkg/coredata/membership_profile.go @@ -1416,6 +1416,11 @@ WHERE _, err := conn.Exec(ctx, q, args) if err != nil { + if pgErr, ok := errors.AsType[*pgconn.PgError](err); ok { + if pgErr.Code == "23503" { + return ErrResourceInUse + } + } return fmt.Errorf("cannot delete profile: %w", err) } diff --git a/pkg/server/api/connect/v1/profile_resolvers.go b/pkg/server/api/connect/v1/profile_resolvers.go index 627e09d0a..13eae79d0 100644 --- a/pkg/server/api/connect/v1/profile_resolvers.go +++ b/pkg/server/api/connect/v1/profile_resolvers.go @@ -120,6 +120,10 @@ func (r *mutationResolver) RemoveUser(ctx context.Context, input types.RemoveUse return nil, gqlutils.Conflict(ctx, err) } + if errors.Is(err, coredata.ErrResourceInUse) { + return nil, gqlutils.Conflict(ctx, err) + } + r.logger.ErrorCtx(ctx, "cannot remove user from organization", log.Error(err)) return nil, gqlutils.Internal(ctx) diff --git a/pkg/server/api/mcp/v1/schema.resolvers.go b/pkg/server/api/mcp/v1/schema.resolvers.go index 9794236dd..8b40607df 100644 --- a/pkg/server/api/mcp/v1/schema.resolvers.go +++ b/pkg/server/api/mcp/v1/schema.resolvers.go @@ -2574,6 +2574,9 @@ func (r *Resolver) RemoveUserTool(ctx context.Context, req *mcp.CallToolRequest, if _, ok := errors.AsType[*iam.ErrLastActiveOwner](err); ok { return nil, types.RemoveUserOutput{}, fmt.Errorf("cannot remove last active owner: %w", err) } + if errors.Is(err, coredata.ErrResourceInUse) { + return nil, types.RemoveUserOutput{}, fmt.Errorf("cannot remove user: %w", err) + } return nil, types.RemoveUserOutput{}, fmt.Errorf("remove user: %w", err) }