Team membership approvals are not final and can be overriden
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 177
- Forks
- 68
- Avg merge
- 2d 22h
- Merged PRs (30d)
- 60
Description
How to use GitHub
- Please use the 👍 reaction to show that you are affected by the same issue.
- Please don't comment if you have no relevant information to add. It's just extra noise for everyone subscribed to this issue.
- Subscribe to receive notifications on status change and new comments.
Steps to reproduce
- Create a new team "team5" as "admin" user
- Add "user1" and "user2"
- Assign an Admin role to user1
- Check/enable team properties:
- Anyone can request membership
- Members need to accept invitation
- Memberships must be confirmed/accepted by a Moderator (requires "Anyone can request membership")
- Visible to everyone
- Switch to "user4" and apply for a request to join team5
- Switch to user1 and approve the request
- (user4 gets added to the team)
- Switch to admin user and reject the request
- (user4 gets removed to the team)
Alternatively, if user1 rejects the request and admin approves it, admin gets a generic error "Failed to perform action" and the network log shows a generic 404.
^This one is a little hard to catch since the notification is removed soon but a helpful message would be nice nonetheless.
Expected behaviour
One approval from the notifications from any one of the admins/moderators should be final, and either the notifications from others users be removed or the actions there should be ignored if the user has been approved already.
Actual behaviour
Rejection from any one of the admins/moderators takes effect and removes the user.
Didn't test subsequent actions from additional admins/moderators from their notifications.
Server configuration
Web server: Apache/Nginx
Database: MySQL/Maria/SQLite/PostgreSQL
PHP version: 8.5/8.4/8.3
Nextcloud version: 34.0.3.2
List of activated apps
- circles: 34.0.0
- contacts: 8.8.0-rc.1
Nextcloud configuration
{
"system": {
"debug": true,
"profiler": true,
"apps_paths": [
{
"path": "\/var\/www\/html\/apps",
"url": "\/apps",
"writable": false
},
{
"path": "\/var\/www\/html\/apps-extra",
"url": "\/apps-extra",
"writable": false
},
{
"path": "\/var\/www\/html\/apps-shared",
"url": "\/apps-shared",
"writable": false
},
{
"path": "\/var\/www\/html\/apps-writable",
"url": "\/apps-writable",
"writable": true
}
],
"allow_local_remote_servers": true,
"mail_from_address": "***REMOVED SENSITIVE VALUE***",
"mail_smtpmode": "smtp",
"mail_sendmailmode": "smtp",
"mail_domain": "***REMOVED SENSITIVE VALUE***",
"mail_smtphost": "***REMOVED SENSITIVE VALUE***",
"mail_smtpport": "1025",
"skeletondirectory": "\/skeleton",
"setup_create_db_user": false,
"loglevel": 2,
"log_query": false,
"query_log_file": "\/shared\/log\/querylog-stable34.log",
"query_log_file_requestid": "yes",
"diagnostics.logging": false,
"diagnostics.logging.threshold": 0,
"log.condition": {
"apps": [
"diagnostics",
"admin_audit"
]
},
"sharing.federation.allowSelfSignedCertificates": true,
"gss.selfsigned.allow": true,
"passwordsalt": "***REMOVED SENSITIVE VALUE***",
"secret": "***REMOVED SENSITIVE VALUE***",
"trusted_domains": [
"localhost",
"nextcloud",
"stable34.nc.ncweb",
"192.168.21.8",
"localhost"
],
"datadirectory": "***REMOVED SENSITIVE VALUE***",
"dbtype": "mysql",
"version": "34.0.3.2",
"overwrite.cli.url": "https:\/\/stable34.nc.ncweb",
"instanceid": "***REMOVED SENSITIVE VALUE***",
"dbname": "***REMOVED SENSITIVE VALUE***",
"dbhost": "***REMOVED SENSITIVE VALUE***",
"dbtableprefix": "oc_",
"mysql.utf8mb4": true,
"dbuser": "***REMOVED SENSITIVE VALUE***",
"dbpassword": "***REMOVED SENSITIVE VALUE***",
"updater.release.channel": "git",
"installed": true,
"lookup_server": "",
"redis": {
"host": "***REMOVED SENSITIVE VALUE***",
"port": 6379
},
"memcache.local": "\\OC\\Memcache\\Redis",
"memcache.locking": "\\OC\\Memcache\\Redis",
"trusted_proxies": "***REMOVED SENSITIVE VALUE***",
"theme": "",
"maintenance": false,
"ldapProviderFactory": "OCA\\User_LDAP\\LDAPProviderFactory"
}
}
Browser
Browser name: Firefox/Chrome/Safari/…
Browser version: 124/125/…
Operating system: Windows/Ubuntu/Mac/…
Server log
when the request if rejected then approved by another moderator:
{"reqId":"xo4Nkmn8kWoMaqBHDmyP","level":3,"time":"2026-08-27T00:29:11+00:00","remoteAddr":"192.168.21.4","user":"admin","app":"circles","method":"PUT","url":"/ocs/v2.php/apps/circles/circles/unA8Pi4zzB18bzD9WRsLZ7Yj6JsyjLC/members/Cd2CGENqqHK1dGpa9wFJJ4tKS9kytwL","scriptName":"/ocs/v2.php","message":"{\"circleId\":\"unA8Pi4zzB18bzD9WRsLZ7Yj6JsyjLC\",\"memberId\":\"Cd2CGENqqHK1dGpa9wFJJ4tKS9kytwL\"}","userAgent":"xxx","version":"34.0.3.2","exception":{"Exception":"OCA\\Circles\\Exceptions\\MemberNotFoundException","Message":"","Code":404,"Trace":[{"file":"/var/www/html/apps-extra/circles/lib/Db/MemberRequest.php","line":393,"function":"getItemFromRequest","class":"OCA\\Circles\\Db\\MemberRequestBuilder","type":"->","args":[{"__class__":"OCA\\Circles\\Db\\CoreQueryBuilder"}]},{"file":"/var/www/html/apps-extra/circles/lib/Service/MemberService.php","line":139,"function":"getMemberById","class":"OCA\\Circles\\Db\\MemberRequest","type":"->","args":["Cd2CGENqqHK1dGpa9wFJJ4tKS9kytwL",{"__class__":"OCA\\Circles\\Model\\FederatedUser"},{"__class__":"OCA\\Circles\\Model\\Probes\\MemberProbe"}]},{"file":"/var/www/html/apps-extra/circles/lib/Controller/LocalController.php","line":376,"function":"getMemberById","class":"OCA\\Circles\\Service\\MemberService","type":"->","args":["Cd2CGENqqHK1dGpa9wFJJ4tKS9kytwL","unA8Pi4zzB18bzD9WRsLZ7Yj6JsyjLC"]},{"file":"/var/www/html/lib/private/AppFramework/Http/Dispatcher.php","line":165,"function":"memberConfirm","class":"OCA\\Circles\\Controller\\LocalController","type":"->","args":["unA8Pi4zzB18bzD9WRsLZ7Yj6JsyjLC","Cd2CGENqqHK1dGpa9wFJJ4tKS9kytwL"]},{"file":"/var/www/html/lib/private/AppFramework/Http/Dispatcher.php","line":78,"function":"executeController","class":"OC\\AppFramework\\Http\\Dispatcher","type":"->","args":[{"__class__":"OCA\\Circles\\Controller\\LocalController"},"memberConfirm"]},{"file":"/var/www/html/lib/private/AppFramework/App.php","line":137,"function":"dispatch","class":"OC\\AppFramework\\Http\\Dispatcher","type":"->","args":[{"__class__":"OCA\\Circles\\Controller\\LocalController"},"memberConfirm"]},{"file":"/var/www/html/lib/private/Route/Router.php","line":324,"function":"main","class":"OC\\AppFramework\\App","type":"::","args":["OCA\\Circles\\Controller\\LocalController","memberConfirm",{"__class__":"OC\\AppFramework\\DependencyInjection\\DIContainer"},{"_route":"ocs.circles.local.memberconfirm","circleId":"unA8Pi4zzB18bzD9WRsLZ7Yj6JsyjLC","memberId":"Cd2CGENqqHK1dGpa9wFJJ4tKS9kytwL"}]},{"file":"/var/www/html/ocs/v1.php","line":78,"function":"match","class":"OC\\Route\\Router","type":"->","args":["/ocsapp/apps/circles/circles/unA8Pi4zzB18bzD9WRsLZ7Yj6JsyjLC/members/Cd2CGENqqHK1dGpa9wFJJ4tKS9kytwL"]},{"file":"/var/www/html/ocs/v2.php","line":10,"args":["/var/www/html/ocs/v1.php"],"function":"require_once"}],"File":"/var/www/html/apps-extra/circles/lib/Db/MemberRequestBuilder.php","Line":102,"message":"{\"circleId\":\"unA8Pi4zzB18bzD9WRsLZ7Yj6JsyjLC\",\"memberId\":\"Cd2CGENqqHK1dGpa9wFJJ4tKS9kytwL\"}","exception":"{\"class\":\"OCA\\Circles\\Exceptions\\MemberNotFoundException\",\"message\":\"\",\"code\":404,\"file\":\"/var/www/html/apps-extra/circles/lib/Db/MemberRequestBuilder.php:102\",\"trace\":\"#0 /var/www/html/apps-extra/circles/lib/Db/MemberRequest.php(393): OCA\\Circles\\Db\\MemberRequestBuilder->getItemFromRequest(Object(OCA\\Circles\\Db\\CoreQueryBuilder))\\n#1 /var/www/html/apps-extra/circles/lib/Service/MemberService.php(139): OCA\\Circles\\Db\\MemberRequest->getMemberById('Cd2CGENqqHK1dGp...', Object(OCA\\Circles\\Model\\FederatedUser), Object(OCA\\Circles\\Model\\Probes\\MemberProbe))\\n#2 /var/www/html/apps-extra/circles/lib/Controller/LocalController.php(376): OCA\\Circles\\Service\\MemberService->getMemberById('Cd2CGENqqHK1dGp...', 'unA8Pi4zzB18bzD...')\\n#3 /var/www/html/lib/private/AppFramework/Http/Dispatcher.php(165): OCA\\Circles\\Controller\\LocalController->memberConfirm('unA8Pi4zzB18bzD...', 'Cd2CGENqqHK1dGp...')\\n#4 /var/www/html/lib/private/AppFramework/Http/Dispatcher.php(78): OC\\AppFramework\\Http\\Dispatcher->executeController(Object(OCA\\Circles\\Controller\\LocalController), 'memberConfirm')\\n#5 /var/www/html/lib/private/AppFramework/App.php(137): OC\\AppFramework\\Http\\Dispatcher->dispatch(Object(OCA\\Circles\\Controller\\LocalController), 'memberConfirm')\\n#6 /var/www/html/lib/private/Route/Router.php(324): OC\\AppFramework\\App::main('OCA\\\\Circles\\\\Con...', 'memberConfirm', Object(OC\\AppFramework\\DependencyInjection\\DIContainer), Array)\\n#7 /var/www/html/ocs/v1.php(78): OC\\Route\\Router->match('/ocsapp/apps/ci...')\\n#8 /var/www/html/ocs/v2.php(10): require_once('/var/www/html/o...')\\n#9 {main}\"}","CustomMessage":"{\"circleId\":\"unA8Pi4zzB18bzD9WRsLZ7Yj6JsyjLC\",\"memberId\":\"Cd2CGENqqHK1dGpa9wFJJ4tKS9kytwL\"}"}}
another error for the same case from a different system, maybe it's useful:
{"reqId":"VItLHnJ6lCJ0QHIpGDjd","level":3,"time":"2026-08-19 11:30:50","remoteAddr":"xxx","user":"TeamModerator","app":"circles","method":"PUT","url":"/ocs/v2.php/apps/circles/circles/FjbM8Rj6TjWUNGUUG2TLIqZ7vyJIbkd/members/NeqYFrRKk2srSmIc3niWcsn9Qg1gSx5","scriptName":"/ocs/v2.php","message":"{\"circleId\":\"FjbM8Rj6TjWUNGUUG2TLIqZ7vyJIbkd\",\"memberId\":\"NeqYFrRKk2srSmIc3niWcsn9Qg1gSx5\"}","userAgent":"xxx","version":"34.0.3.2","exception":{"Exception":"OCA\\Circles\\Exceptions\\FederatedItemBadRequestException","Message":"Already member of the team","Code":122,"Trace":[{"file":"/var/www/html/nextcloud/apps/circles/lib/FederatedItems/SingleMemberAdd.php","line":243,"function":"manageMemberStatus","class":"OCA\\Circles\\FederatedItems\\SingleMemberAdd","type":"->"},{"file":"/var/www/html/nextcloud/apps/circles/lib/FederatedItems/SingleMemberAdd.php","line":114,"function":"generateMember","class":"OCA\\Circles\\FederatedItems\\SingleMemberAdd","type":"->"},{"file":"/var/www/html/nextcloud/apps/circles/lib/Service/FederatedEventService.php","line":116,"function":"verify","class":"OCA\\Circles\\FederatedItems\\SingleMemberAdd","type":"->"},{"file":"/var/www/html/nextcloud/apps/circles/lib/Service/MemberService.php","line":223,"function":"newEvent","class":"OCA\\Circles\\Service\\FederatedEventService","type":"->"},{"file":"/var/www/html/nextcloud/apps/circles/lib/Controller/LocalController.php","line":380,"function":"addMember","class":"OCA\\Circles\\Service\\MemberService","type":"->"},{"file":"/var/www/html/nextcloud/lib/private/AppFramework/Http/Dispatcher.php","line":165,"function":"memberConfirm","class":"OCA\\Circles\\Controller\\LocalController","type":"->"},{"file":"/var/www/html/nextcloud/lib/private/AppFramework/Http/Dispatcher.php","line":78,"function":"executeController","class":"OC\\AppFramework\\Http\\Dispatcher","type":"->"},{"file":"/var/www/html/nextcloud/lib/private/AppFramework/App.php","line":137,"function":"dispatch","class":"OC\\AppFramework\\Http\\Dispatcher","type":"->"},{"file":"/var/www/html/nextcloud/lib/private/Route/Router.php","line":324,"function":"main","class":"OC\\AppFramework\\App","type":"::"},{"file":"/var/www/html/nextcloud/ocs/v1.php","line":78,"function":"match","class":"OC\\Route\\Router","type":"->"},{"file":"/var/www/html/nextcloud/ocs/v2.php","line":10,"args":["/var/www/html/nextcloud/ocs/v1.php"],"function":"require_once"}],"File":"/var/www/html/nextcloud/apps/circles/lib/FederatedItems/SingleMemberAdd.php","Line":296,"message":"{\"circleId\":\"FjbM8Rj6TjWUNGUUG2TLIqZ7vyJIbkd\",\"memberId\":\"NeqYFrRKk2srSmIc3niWcsn9Qg1gSx5\"}","exception":"{\"class\":\"OCA\\Circles\\Exceptions\\FederatedItemBadRequestException\",\"message\":\"Already member of the team\",\"code\":122,\"file\":\"/var/www/html/nextcloud/apps/circles/lib/FederatedItems/SingleMemberAdd.php:296\",\"trace\":\"#0 /var/www/html/nextcloud/apps/circles/lib/FederatedItems/SingleMemberAdd.php(243): OCA\\Circles\\FederatedItems\\SingleMemberAdd->manageMemberStatus()\\n#1 /var/www/html/nextcloud/apps/circles/lib/FederatedItems/SingleMemberAdd.php(114): OCA\\Circles\\FederatedItems\\SingleMemberAdd->generateMember()\\n#2 /var/www/html/nextcloud/apps/circles/lib/Service/FederatedEventService.php(116): OCA\\Circles\\FederatedItems\\SingleMemberAdd->verify()\\n#3 /var/www/html/nextcloud/apps/circles/lib/Service/MemberService.php(223): OCA\\Circles\\Service\\FederatedEventService->newEvent()\\n#4 /var/www/html/nextcloud/apps/circles/lib/Controller/LocalController.php(380): OCA\\Circles\\Service\\MemberService->addMember()\\n#5 /var/www/html/nextcloud/lib/private/AppFramework/Http/Dispatcher.php(165): OCA\\Circles\\Controller\\LocalController->memberConfirm()\\n#6 /var/www/html/nextcloud/lib/private/AppFramework/Http/Dispatcher.php(78): OC\\AppFramework\\Http\\Dispatcher->executeController()\\n#7 /var/www/html/nextcloud/lib/private/AppFramework/App.php(137): OC\\AppFramework\\Http\\Dispatcher->dispatch()\\n#8 /var/www/html/nextcloud/lib/private/Route/Router.php(324): OC\\AppFramework\\App::main()\\n#9 /var/www/html/nextcloud/ocs/v1.php(78): OC\\Route\\Router->match()\\n#10 /var/www/html/nextcloud/ocs/v2.php(10): require_once('...')\\n#11 {main}\"}","CustomMessage":"{\"circleId\":\"FjbM8Rj6TjWUNGUUG2TLIqZ7vyJIbkd\",\"memberId\":\"NeqYFrRKk2srSmIc3niWcsn9Qg1gSx5\"}"}}
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at apps-extra/circles/lib/Controller/LocalController.php memberConfirm, then trace MemberService.php, MemberRequest.php, and MemberRequestBuilder.php. Review the approval path and the related SingleMemberAdd.php flow shown in the logs. Done means one moderator’s approval is final, later stale actions do not undo it, and repeated approval produces a useful result instead of a generic 404.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- php
- Domain
- api, authorization, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100