Skip to content

fix(files_sharing): skip unresolvable share recipients - #62368

Merged
nickvergessen merged 1 commit into
masterfrom
fix/18415/talk-share-fail-for-orphan-user
Aug 5, 2026
Merged

fix(files_sharing): skip unresolvable share recipients#62368
nickvergessen merged 1 commit into
masterfrom
fix/18415/talk-share-fail-for-orphan-user

Conversation

@Antreesy

@Antreesy Antreesy commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Summary

in SharesUpdatedListener, a share recipient may reference a user id that no backend can resolve anymore (e.g. with LazyUser::getUID()) - like remnant / incorrectly removed user.

Example: Talk application supplies LazyUsers from oc_talk_attendees table, which can get desynced from the user backend (e.g. LDAP entries)

Skip this recipient instead of aborting the share operation resolve the issue. As listener is running as a post-effect, and share is already created (at least to the room -> to the group), it should be a safe reason to catch and skip?

To test:

  1. Easiest path: create a rogue entry in oc_talk_attendees, with non-existing id, omit capability 'conversation-subfolders' to utilize legacy share mechanism (each file is separate share), share a file to the room => POST request should fail with 500
  2. Complicated path: find a way for LDAP to clear mapping / execute similar flow to leave a rogur entry, then same as in opt.1

TODO

  • Sanity check
  • Possible side-effects?
  • For backports - should use OC\User\NoUserException ?

Checklist

AI (if applicable)

  • The content of this PR was partly or fully generated using AI
@Antreesy Antreesy added this to the Nextcloud 35 milestone Jul 21, 2026
@Antreesy Antreesy self-assigned this Jul 21, 2026
@Antreesy
Antreesy requested a review from a team as a code owner July 21, 2026 14:48
@Antreesy
Antreesy requested review from leftybournes and salmart-dev and removed request for a team July 21, 2026 14:48
@@ -135,7 +136,17 @@ private function markOrRun(IUser $user, callable $callback): void {
$elapsed = $now - $this->firstRun;

if ($this->cutOffMarkTime === -1.0 || $elapsed < $this->cutOffMarkTime) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought === on float was not possible 🤔 Should this be < 0? (unrelated to this PR)

// A share recipient may reference a user id that no backend can resolve anymore
// (e.g. with LazyUser::getUID()) - like remnant / incorrectly removed user.
// Skip this recipient instead of aborting the share operation.
$this->logger->warning(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think debug level is enough. Also, no need to specify 'app' in the logger context, that’s automatically injected.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the plausible ticket scenario (deleted/fake/unresolvable user is missing a share), agree that debug is probably enough

@Antreesy
Antreesy force-pushed the fix/18415/talk-share-fail-for-orphan-user branch from d2ed18f to 847501c Compare August 3, 2026 09:48
@come-nc

come-nc commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

I opened #62791 for another issue but of the same kind.
I’m not sure whether it also fixes this issue, because I’m not sure what the $listener() call is.

@Antreesy

Antreesy commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

I’m not sure whether it also fixes this issue, because I’m not sure what the $listener() call is.

Tested with my reproduction steps, sadly it doesn't get caught on your branch:

{"reqId":"UgIT9iJaKsrzp4ZpNtzC","level":3,"time":"2026-08-03T17:01:00+00:00","remoteAddr":"192.168.21.9","user":"admin","app":"no app in context","method":"POST","url":"/ocs/v2.php/apps/files_sharing/api/v1/shares","scriptName":"/ocs/v2.php","message":"Error while sending 'share created' event","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36","version":"35.0.0.1","exception":{"Exception":"OC\\User\\NoUserException","Message":"Backends provided no user object","Code":0,"Trace":[{"function":"getUserFolder","class":"OC\\Files\\Node\\Root","type":"->","args":["bob2"]},{"file":"/var/www/html/lib/private/Files/Node/LazyFolder.php","line":67,"function":"call_user_func_array","args":[[{"__class__":"OC\\Files\\Node\\Root"},"getUserFolder"],["bob2"]]},{"file":"/var/www/html/lib/private/Files/Node/LazyRoot.php","line":41,"function":"__call","class":"OC\\Files\\Node\\LazyFolder","type":"->","args":["getUserFolder",["bob2"]]},{"file":"/var/www/html/apps/files_sharing/lib/ShareTargetValidator.php","line":70,"function":"getUserFolder","class":"OC\\Files\\Node\\LazyRoot","type":"->","args":["bob2"]},{"file":"/var/www/html/apps/files_sharing/lib/ShareRecipientUpdater.php","line":77,"function":"verifyMountPoint","class":"OCA\\Files_Sharing\\ShareTargetValidator","type":"->","args":["*** sensitive parameters replaced ***","*** sensitive parameters replaced ***",{"__class__":"Closure"},["*** sensitive parameters replaced ***"]]},{"file":"/var/www/html/apps/files_sharing/lib/Listener/SharesUpdatedListener.php","line":98,"function":"updateForAddedShare","class":"OCA\\Files_Sharing\\ShareRecipientUpdater","type":"->","args":["*** sensitive parameters replaced ***"]},{"file":"/var/www/html/apps/files_sharing/lib/Listener/SharesUpdatedListener.php","line":138,"function":"{closure:OCA\\Files_Sharing\\Listener\\SharesUpdatedListener::handle():97}","class":"OCA\\Files_Sharing\\Listener\\SharesUpdatedListener","type":"->","args":["*** sensitive parameters replaced ***"]},{"file":"/var/www/html/apps/files_sharing/lib/Listener/SharesUpdatedListener.php","line":97,"function":"markOrRun","class":"OCA\\Files_Sharing\\Listener\\SharesUpdatedListener","type":"->","args":["*** sensitive parameters replaced ***",{"__class__":"Closure"}]},{"file":"/var/www/html/lib/private/EventDispatcher/ServiceEventListener.php","line":57,"function":"handle","class":"OCA\\Files_Sharing\\Listener\\SharesUpdatedListener","type":"->","args":[{"__class__":"OCP\\Share\\Events\\ShareCreatedEvent"}]},{"file":"/var/www/html/3rdparty/symfony/event-dispatcher/EventDispatcher.php","line":220,"function":"__invoke","class":"OC\\EventDispatcher\\ServiceEventListener","type":"->","args":[{"__class__":"OCP\\Share\\Events\\ShareCreatedEvent"},"OCP\\Share\\Events\\ShareCreatedEvent",{"__class__":"Symfony\\Component\\EventDispatcher\\EventDispatcher"}]},{"file":"/var/www/html/3rdparty/symfony/event-dispatcher/EventDispatcher.php","line":56,"function":"callListeners","class":"Symfony\\Component\\EventDispatcher\\EventDispatcher","type":"->","args":[[{"__class__":"Closure"},{"__class__":"Closure"},{"__class__":"Closure"},{"__class__":"Closure"},{"__class__":"Closure"},"And 5 more entries, set log level to debug to see all entries"],"OCP\\Share\\Events\\ShareCreatedEvent",{"__class__":"OCP\\Share\\Events\\ShareCreatedEvent"}]},{"file":"/var/www/html/lib/private/EventDispatcher/EventDispatcher.php","line":74,"function":"dispatch","class":"Symfony\\Component\\EventDispatcher\\EventDispatcher","type":"->","args":[{"__class__":"OCP\\Share\\Events\\ShareCreatedEvent"},"OCP\\Share\\Events\\ShareCreatedEvent"]},{"file":"/var/www/html/lib/private/EventDispatcher/EventDispatcher.php","line":87,"function":"dispatch","class":"OC\\EventDispatcher\\EventDispatcher","type":"->","args":["OCP\\Share\\Events\\ShareCreatedEvent",{"__class__":"OCP\\Share\\Events\\ShareCreatedEvent"}]},{"file":"/var/www/html/lib/private/Share20/Manager.php","line":1897,"function":"dispatchTyped","class":"OC\\EventDispatcher\\EventDispatcher","type":"->","args":[{"__class__":"OCP\\Share\\Events\\ShareCreatedEvent"}]},{"file":"/var/www/html/lib/private/Share20/Manager.php","line":637,"function":"dispatchEvent","class":"OC\\Share20\\Manager","type":"->","args":[{"__class__":"OCP\\Share\\Events\\ShareCreatedEvent"},"share created"]},{"file":"/var/www/html/apps/files_sharing/lib/Controller/ShareAPIController.php","line":813,"function":"createShare","class":"OC\\Share20\\Manager","type":"->","args":["*** sensitive parameters replaced ***"]},{"file":"/var/www/html/lib/private/AppFramework/Http/Dispatcher.php","line":172,"function":"createShare","class":"OCA\\Files_Sharing\\Controller\\ShareAPIController","type":"->","args":["*** sensitive parameters replaced ***"]},{"file":"/var/www/html/lib/private/AppFramework/Http/Dispatcher.php","line":80,"function":"executeController","class":"OC\\AppFramework\\Http\\Dispatcher","type":"->","args":[{"__class__":"OCA\\Files_Sharing\\Controller\\ShareAPIController"},"createShare"]},{"file":"/var/www/html/lib/private/AppFramework/App.php","line":138,"function":"dispatch","class":"OC\\AppFramework\\Http\\Dispatcher","type":"->","args":[{"__class__":"OCA\\Files_Sharing\\Controller\\ShareAPIController"},"createShare"]},{"file":"/var/www/html/lib/private/Route/Router.php","line":324,"function":"main","class":"OC\\AppFramework\\App","type":"::","args":["OCA\\Files_Sharing\\Controller\\ShareAPIController","createShare",{"__class__":"OC\\AppFramework\\DependencyInjection\\DIContainer"},{"_route":"ocs.files_sharing.shareapi.createshare"}]},{"file":"/var/www/html/ocs/v1.php","line":78,"function":"match","class":"OC\\Route\\Router","type":"->","args":["/ocsapp/apps/files_sharing/api/v1/shares"]},{"file":"/var/www/html/ocs/v2.php","line":10,"args":["/var/www/html/ocs/v1.php"],"function":"require_once"}],"File":"/var/www/html/lib/private/Files/Node/Root.php","Line":325,"message":"Error while sending 'share created' event","exception":"{\"class\":\"OC\\User\\NoUserException\",\"message\":\"Backends provided no user object\",\"code\":0,\"file\":\"/var/www/html/lib/private/Files/Node/Root.php:325\",\"trace\":\"#0 [internal function]: OC\\Files\\Node\\Root->getUserFolder('bob2')\\n#1 /var/www/html/lib/private/Files/Node/LazyFolder.php(67): call_user_func_array(Array, Array)\\n#2 /var/www/html/lib/private/Files/Node/LazyRoot.php(41): OC\\Files\\Node\\LazyFolder->__call('getUserFolder', Array)\\n#3 /var/www/html/apps/files_sharing/lib/ShareTargetValidator.php(70): OC\\Files\\Node\\LazyRoot->getUserFolder('bob2')\\n#4 /var/www/html/apps/files_sharing/lib/ShareRecipientUpdater.php(77): OCA\\Files_Sharing\\ShareTargetValidator->verifyMountPoint(Object(OC\\User\\LazyUser), Object(OC\\Share20\\Share), Object(Closure), Array)\\n#5 /var/www/html/apps/files_sharing/lib/Listener/SharesUpdatedListener.php(98): OCA\\Files_Sharing\\ShareRecipientUpdater->updateForAddedShare(Object(OC\\User\\LazyUser), Object(OC\\Share20\\Share))\\n#6 /var/www/html/apps/files_sharing/lib/Listener/SharesUpdatedListener.php(138): OCA\\Files_Sharing\\Listener\\SharesUpdatedListener->{closure:OCA\\Files_Sharing\\Listener\\SharesUpdatedListener::handle():97}()\\n#7 /var/www/html/apps/files_sharing/lib/Listener/SharesUpdatedListener.php(97): OCA\\Files_Sharing\\Listener\\SharesUpdatedListener->markOrRun(Object(OC\\User\\LazyUser), Object(Closure))\\n#8 /var/www/html/lib/private/EventDispatcher/ServiceEventListener.php(57): OCA\\Files_Sharing\\Listener\\SharesUpdatedListener->handle(Object(OCP\\Share\\Events\\ShareCreatedEvent))\\n#9 /var/www/html/3rdparty/symfony/event-dispatcher/EventDispatcher.php(220): OC\\EventDispatcher\\ServiceEventListener->__invoke(Object(OCP\\Share\\Events\\ShareCreatedEvent), 'OCP\\\\Share\\\\Event...', Object(Symfony\\Component\\EventDispatcher\\EventDispatcher))\\n#10 /var/www/html/3rdparty/symfony/event-dispatcher/EventDispatcher.php(56): Symfony\\Component\\EventDispatcher\\EventDispatcher->callListeners(Array, 'OCP\\\\Share\\\\Event...', Object(OCP\\Share\\Events\\ShareCreatedEvent))\\n#11 /var/www/html/lib/private/EventDispatcher/EventDispatcher.php(74): Symfony\\Component\\EventDispatcher\\EventDispatcher->dispatch(Object(OCP\\Share\\Events\\ShareCreatedEvent), 'OCP\\\\Share\\\\Event...')\\n#12 /var/www/html/lib/private/EventDispatcher/EventDispatcher.php(87): OC\\EventDispatcher\\EventDispatcher->dispatch('OCP\\\\Share\\\\Event...', Object(OCP\\Share\\Events\\ShareCreatedEvent))\\n#13 /var/www/html/lib/private/Share20/Manager.php(1897): OC\\EventDispatcher\\EventDispatcher->dispatchTyped(Object(OCP\\Share\\Events\\ShareCreatedEvent))\\n#14 /var/www/html/lib/private/Share20/Manager.php(637): OC\\Share20\\Manager->dispatchEvent(Object(OCP\\Share\\Events\\ShareCreatedEvent), 'share created')\\n#15 /var/www/html/apps/files_sharing/lib/Controller/ShareAPIController.php(813): OC\\Share20\\Manager->createShare(Object(OC\\Share20\\Share))\\n#16 /var/www/html/lib/private/AppFramework/Http/Dispatcher.php(172): OCA\\Files_Sharing\\Controller\\ShareAPIController->createShare('/Talk/vertical ...', 19, 10, '3579626860', NULL, '', NULL, NULL, '', '', NULL, NULL)\\n#17 /var/www/html/lib/private/AppFramework/Http/Dispatcher.php(80): OC\\AppFramework\\Http\\Dispatcher->executeController(Object(OCA\\Files_Sharing\\Controller\\ShareAPIController), 'createShare')\\n#18 /var/www/html/lib/private/AppFramework/App.php(138): OC\\AppFramework\\Http\\Dispatcher->dispatch(Object(OCA\\Files_Sharing\\Controller\\ShareAPIController), 'createShare')\\n#19 /var/www/html/lib/private/Route/Router.php(324): OC\\AppFramework\\App::main('OCA\\\\Files_Shari...', 'createShare', Object(OC\\AppFramework\\DependencyInjection\\DIContainer), Array)\\n#20 /var/www/html/ocs/v1.php(78): OC\\Route\\Router->match('/ocsapp/apps/fi...')\\n#21 /var/www/html/ocs/v2.php(10): require_once('/var/www/html/o...')\\n#22 {main}\"}","CustomMessage":"Error while sending 'share created' event"}}
@nickvergessen

Copy link
Copy Markdown
Member

Would be good to merge for the maintenance release RC this week?

Assisted-by: ClaudeCode:claude-opus-4-8
Signed-off-by: Maksim Sukharev <antreesy.web@gmail.com>
@Antreesy
Antreesy force-pushed the fix/18415/talk-share-fail-for-orphan-user branch from 847501c to 7a2150d Compare August 4, 2026 15:23
@Antreesy

Antreesy commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

/backport to stable34

@Antreesy

Antreesy commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

/backport to stable33

@Antreesy
Antreesy enabled auto-merge August 5, 2026 08:33
@nickvergessen
nickvergessen disabled auto-merge August 5, 2026 09:17
@nickvergessen
nickvergessen merged commit c857bb9 into master Aug 5, 2026
238 of 240 checks passed
@nickvergessen
nickvergessen deleted the fix/18415/talk-share-fail-for-orphan-user branch August 5, 2026 09:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment