{"record":{"id":"46fd85a20fc3ccbc","repo":"plandex-ai/plandex","slug":"error-deleting-org-member-v","errorCode":null,"errorMessage":"error deleting org member: %v","messagePattern":"error deleting org member: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/server/db/org_helpers.go","lineNumber":187,"sourceCode":"\t\t// Join all value strings and execute a single query\n\t\tstmt := fmt.Sprintf(\"INSERT INTO orgs_users (org_id, user_id, org_role_id) VALUES %s ON CONFLICT ON CONSTRAINT org_user_unique DO NOTHING\", strings.Join(valueStrings, \",\"))\n\t\t_, err = tx.Exec(stmt, valueArgs...)\n\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error adding org users: %v\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc DeleteOrgUser(orgId, userId string, tx *sqlx.Tx) error {\n\tlog.Printf(\"Deleting org user, org: %s | user: %s\\n\", orgId, userId)\n\n\t_, err := tx.Exec(\"DELETE FROM orgs_users WHERE org_id = $1 AND user_id = $2\", orgId, userId)\n\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error deleting org member: %v\", err)\n\t}\n\n\treturn nil\n}\n\nfunc CreateOrgUser(orgId, userId, orgRoleId string, tx *sqlx.Tx) error {\n\tquery := \"INSERT INTO orgs_users (org_id, user_id, org_role_id) VALUES ($1, $2, $3)\"\n\tvar err error\n\tif tx == nil {\n\t\t_, err = Conn.Exec(query, orgId, userId, orgRoleId)\n\t} else {\n\t\t_, err = tx.Exec(query, orgId, userId, orgRoleId)\n\t}\n\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error adding org member: %v\", err)\n\t}\n","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/db/org_helpers.go#L169-L205","documentation":"DeleteOrgUser wraps a failure of the DELETE FROM orgs_users into 'error deleting org member: %v'. Unlike a missing row (DELETE simply affects 0 rows and returns nil), this always means the statement itself errored.","triggerScenarios":"tx.Exec('DELETE ...') fails: FK violation on rows referencing orgs_users (e.g. 23503 from dependent tables without ON DELETE), permission denied, connection drop, or aborted transaction from an earlier statement in DeleteOrgUserHandler's tx.","commonSituations":"Trying to remove a user who has dependent records (invites, api keys, session rows) tied by FK; DB role lacking DELETE privilege; connection reset mid-transaction.","solutions":["Read the wrapped %v for pq error code 23503 and add ON DELETE CASCADE or explicit cleanup of dependent rows in the same transaction before the delete","Verify the DB user has DELETE privilege on orgs_users","If the tx was aborted earlier, fix the first failing statement — this error is secondary","Retry the removal after resolving the constraint"],"exampleFix":"// before\n_, err := tx.Exec(\"DELETE FROM orgs_users WHERE org_id = $1 AND user_id = $2\", orgId, userId)\n// after\n// in migration: dependent tables reference orgs_users(id) ON DELETE CASCADE\n_, err := tx.Exec(\"DELETE FROM orgs_users WHERE org_id = $1 AND user_id = $2\", orgId, userId)","handlingStrategy":"try-catch","validationCode":"// Pre-check membership before delete\nok, err := db.ValidateOrgMembership(orgId, userId)\nif err != nil || !ok { return fmt.Errorf(\"not a member\") }","typeGuard":null,"tryCatchPattern":"err := db.DeleteOrgUser(orgId, userId, tx)\nif err != nil {\n    var pqErr *pq.Error\n    if errors.As(err, &pqErr) && pqErr.Code == \"23503\" {\n        return fmt.Errorf(\"member has dependent records: %s\", pqErr.Detail)\n    }\n    return err\n}","preventionTips":["Add ON DELETE CASCADE (or explicit cleanup) for tables referencing orgs_users","Clean dependent rows in the same tx before the delete","Grant the app role DELETE privilege on orgs_users","Distinguish 0-rows-deleted (not a member) from statement errors by checking RowsAffected if needed"],"tags":["database","postgresql","delete-failure","foreign-key"],"backgroundTag":"foreign-key-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"}