{"record":{"id":"b74c33d7a6b940b1","repo":"plandex-ai/plandex","slug":"error-deleting-invite-v-b74c33","errorCode":null,"errorMessage":"error deleting invite: %v","messagePattern":"error deleting invite: (.+?)","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"app/server/handlers/users.go","lineNumber":209,"sourceCode":"\n\t\tif err != nil {\n\t\t\tlog.Println(\"Error deleting org user: \", err)\n\t\t\treturn fmt.Errorf(\"error deleting org user: %v\", err)\n\t\t}\n\n\t\tinvite, err := db.GetActiveInviteByEmail(auth.OrgId, auth.User.Email)\n\n\t\tif err != nil {\n\t\t\tlog.Println(\"Error getting invite for org user: \", err)\n\t\t\treturn fmt.Errorf(\"error getting invite for org user: %v\", err)\n\t\t}\n\n\t\tif invite != nil {\n\t\t\terr = db.DeleteInvite(invite.Id, tx)\n\n\t\t\tif err != nil {\n\t\t\t\tlog.Println(\"Error deleting invite: \", err)\n\t\t\t\treturn fmt.Errorf(\"error deleting invite: %v\", err)\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t})\n\n\tif err != nil {\n\t\tlog.Println(\"Error deleting org user: \", err)\n\t\thttp.Error(w, \"Error deleting org user: \"+err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tlog.Println(\"Successfully processed request for DeleteOrgUserHandler\")\n}\n","sourceCodeStart":191,"sourceCodeEnd":224,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/handlers/users.go#L191-L224","documentation":"If an active invite exists, the handler deletes it with db.DeleteInvite inside the same transaction. Failure here rolls back the whole org-user deletion and returns the wrapped 'error deleting invite' error as HTTP 500.","triggerScenarios":"db.DeleteInvite fails: the invite row was already deleted by a concurrent request, FK reference to the invite from another table, deadlock with a parallel deletion, or DB connection loss.","commonSituations":"Race between deleting the user from two sessions (invite deleted in one, delete fails in the other); invites referenced by audit/notification rows; transaction deadlocks under concurrent admin operations.","solutions":["Inspect the wrapped cause; check for 'no rows' / duplicate-deletion races and treat already-deleted as success.","Remove FK references to the invite or enable cascading deletes.","Retry on transient errors (deadlock, serialization) with backoff.","Serialize user-removal operations per user (lock or idempotency key)."],"exampleFix":"// before\nerr = db.DeleteInvite(invite.Id, tx)\nif err != nil { return fmt.Errorf(\"error deleting invite: %v\", err) }\n// after\nerr = db.DeleteInvite(invite.Id, tx)\nif errors.Is(err, sql.ErrNoRows) {\n    return nil // already deleted\n}\nif err != nil { return fmt.Errorf(\"error deleting invite: %v\", err) }","handlingStrategy":"validation","validationCode":"// Go - check invite still exists before deleting inside the tx\ninvite, err := db.GetActiveInviteByEmail(auth.OrgId, auth.User.Email)\nif err != nil || invite == nil {\n    return nil // nothing to delete\n}","typeGuard":"func inviteDeletable(invite *db.Invite) bool { return invite != nil && invite.Id != \"\" }","tryCatchPattern":"err = db.DeleteInvite(invite.Id, tx)\nif errors.Is(err, sql.ErrNoRows) {\n    return nil // already deleted concurrently\n}\nif err != nil {\n    return fmt.Errorf(\"error deleting invite: %v\", err)\n}","preventionTips":["Make invite deletion idempotent (no-op if already gone).","Avoid parallel admin operations on the same user.","Use row-level locking or unique constraints to serialize races.","Enable cascading deletes for rows referencing invites."],"tags":["database","go","transaction"],"backgroundTag":"database-constraint-violation","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}