{"record":{"id":"4e4adebe5eb5f1ea","repo":"nextcloud/server","slug":"adding-members-to-remote-user-is-not-supported","errorCode":null,"errorMessage":"Adding members to remote user is not supported","messagePattern":"Adding members to remote user is not supported","errorType":"exception","errorClass":"Sabre\\DAV\\Exception","httpStatus":500,"severity":"warning","filePath":"apps/dav/lib/DAV/RemoteUserPrincipalBackend.php","lineNumber":110,"sourceCode":"\t#[\\Override]\n\tpublic function getGroupMemberSet($principal) {\n\t\treturn [];\n\t}\n\n\t#[\\Override]\n\tpublic function getGroupMembership($principal) {\n\t\t// TODO: for now the group principal has only one member, the user itself\n\t\t$principal = $this->getPrincipalByPath($principal);\n\t\tif (!$principal) {\n\t\t\tthrow new \\Sabre\\DAV\\Exception('Principal not found');\n\t\t}\n\n\t\treturn [$principal['uri']];\n\t}\n\n\t#[\\Override]\n\tpublic function setGroupMemberSet($principal, array $members) {\n\t\tthrow new \\Sabre\\DAV\\Exception('Adding members to remote user is not supported');\n\t}\n\n\t/**\n\t * @return array{'{DAV:}displayname': string, '{http://nextcloud.com/ns}cloud-id': ICloudId, uri: string}\n\t */\n\tprivate function principalUriToPrincipal(string $principalUri): array {\n\t\t[, $name] = \\Sabre\\Uri\\split($principalUri);\n\t\t$cloudId = $this->cloudIdManager->resolveCloudId(base64_decode($name));\n\t\treturn [\n\t\t\t'uri' => $principalUri,\n\t\t\t'{DAV:}displayname' => $cloudId->getDisplayId(),\n\t\t\t'{http://nextcloud.com/ns}cloud-id' => $cloudId,\n\t\t];\n\t}\n\n\tprivate function loadChildren(): void {\n\t\t$rows = $this->sharingMapper->getPrincipalUrisByPrefix('calendar', self::PRINCIPAL_PREFIX);\n\t\t$this->principals = array_map(","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/nextcloud/server/blob/ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3/apps/dav/lib/DAV/RemoteUserPrincipalBackend.php#L92-L128","documentation":"RemoteUserPrincipalBackend::setGroupMemberSet() (apps/dav/lib/DAV/RemoteUserPrincipalBackend.php:110) unconditionally throws \\Sabre\\DAV\\Exception. It implements Sabre's IPrincipalBackend contract, but group membership for a federated remote user cannot be modified locally: the remote user belongs to its own home server, and this backend models the user as a single-member 'group' (see getGroupMembership returning only the principal's own uri).","triggerScenarios":"Any DAV operation that attempts to change the member set of a remote-user principal group — e.g. a CalDAV scheduling or ACL client issuing GROUP-MEMBER-SET PROPPATCH on principals/system/<base64-id>.","commonSituations":"Generic WebDAV admin tooling that walks all group principals and tries to synchronize members; clients implementing ACL group management blindly against every principal collection.","solutions":["Never attempt to modify members of remote user principals; membership is fixed (the user itself).","Manage real groups via the local principals/users and groups backends or the provisioning API (OCS).","Filter client-side: skip principals backed by RemoteUserPrincipalBackend (remote-user collections) when offering group editing.","Treat the resulting 500 as 'not supported' and continue other work."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// never call setGroupMemberSet on remote user principals\nif (!str_contains($principalUri, 'remote') && isLocalGroupPrincipal($principalUri)) {\n    $backend->setGroupMemberSet($principalUri, $members);\n} else {\n    $this->skip('Membership edits unsupported for ' . $principalUri);\n}","typeGuard":"function supportsMemberSetEdit(string $principalUri): bool {\n    return (bool)preg_match('#^principals/groups/[^/]+$#', $principalUri);\n}","tryCatchPattern":"try {\n    $backend->setGroupMemberSet($path, $members);\n} catch (\\Sabre\\DAV\\Exception $e) {\n    if (str_contains($e->getMessage(), 'not supported')) {\n        // expected for read-only backends: log and continue\n        return;\n    }\n    throw $e;\n}","preventionTips":["Offer group editing only for principals actually backed by an editable backend.","Use the provisioning API for real group membership changes.","Treat 'not supported' DAV exceptions on write as capability gaps, not transient errors."],"tags":["dav","principal","group-membership","federation","unsupported"],"backgroundTag":"unsupported-operation","analyzedSha":"ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3","analyzedAt":"2026-08-17T01:36:13.386Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}