{"record":{"id":"e869e8b765d3665a","repo":"plandex-ai/plandex","slug":"error-getting-invite-for-org-user-v","errorCode":null,"errorMessage":"error getting invite for org user: %v","messagePattern":"error getting invite for org user: (.+?)","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"app/server/handlers/users.go","lineNumber":201,"sourceCode":"\t\t\thttp.Error(w, \"Cannot delete the only org owner\", http.StatusForbidden)\n\t\t\treturn\n\t\t}\n\t}\n\n\terr = db.WithTx(r.Context(), \"delete org user\", func(tx *sqlx.Tx) error {\n\n\t\terr = db.DeleteOrgUser(auth.OrgId, userId, tx)\n\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","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/handlers/users.go#L183-L219","documentation":"After deleting the org user inside the same transaction, the handler looks up an active invite for the deleted user's email via db.GetActiveInviteByEmail. If that query errors (not 'no rows' — an actual failure), the tx is rolled back and the wrapped error is returned as HTTP 500.","triggerScenarios":"The invite lookup query fails: DB unreachable, connection pool exhaustion, SQL/schema error in the invites table, or cancellation of the request context mid-transaction.","commonSituations":"Database outage during user offboarding; invites schema migration missing; context canceled by client disconnect mid-tx (context canceled errors).","solutions":["Check the wrapped cause; distinguish real errors from sql.ErrNoRows (which is handled as nil invite).","Verify DB connectivity and pool health.","Confirm the invites table/migrations exist in the environment.","Retry the deletion if the failure was transient (connection, context canceled)."],"exampleFix":"// before\ninvite, err := db.GetActiveInviteByEmail(auth.OrgId, auth.User.Email)\nif err != nil { return fmt.Errorf(\"error getting invite for org user: %v\", err) }\n// after\ninvite, err := db.GetActiveInviteByEmail(auth.OrgId, auth.User.Email)\nif errors.Is(err, sql.ErrNoRows) {\n    return nil\n} else if err != nil {\n    return fmt.Errorf(\"error getting invite for org user: %v\", err)\n}","handlingStrategy":"try-catch","validationCode":"// Go\nif err := db.PingContext(ctx); err != nil {\n    return fmt.Errorf(\"db unavailable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"invite, err := db.GetActiveInviteByEmail(auth.OrgId, auth.User.Email)\nif errors.Is(err, sql.ErrNoRows) {\n    return nil // no invite; not an error\n}\nif err != nil {\n    return fmt.Errorf(\"error getting invite for org user: %v\", err)\n}","preventionTips":["Treat sql.ErrNoRows separately from real query errors.","Keep invites schema migrations applied in all environments.","Monitor DB health during user-management operations.","Use contexts with sane timeouts for tx queries."],"tags":["database","go","postgres"],"backgroundTag":"database-query-failed","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"}