nextcloud/server · error · Sabre\DAV\Exception\BadRequest
{http://owncloud.org/ns}share needs at least one set or remo
Error message
{http://owncloud.org/ns}share needs at least one set or remove element What it means
HTTP 400 BadRequest from validateShareRequest() when the deserialized ShareRequest contains zero set elements and zero remove elements (count($shareRequest->set) + count($shareRequest->remove) === 0). A share POST that changes nothing is rejected as invalid before updateShares() runs.
Source
Thrown at apps/dav/lib/DAV/Sharing/Plugin.php:184
// Adding this because sending a response body may cause issues,
// and I wanted some type of indicator the response was handled.
$response->setHeader('X-Sabre-Status', 'everything-went-well');
// Breaking the event chain
return false;
}
}
private function validateShareRequest($shareRequest): void {
if (!$shareRequest instanceof ShareRequest) {
// @FIXME: Replace switch-case in httpPost with instanceof ShareRequest
throw new BadRequest('The given request is not valid');
}
$elements = (count($shareRequest->set) + count($shareRequest->remove));
if ($elements === 0) {
throw new BadRequest(ShareRequest::ELEMENT_SHARE . ' needs at least one set or remove element');
}
if ($elements > 10) {
throw new BadRequest(ShareRequest::ELEMENT_SHARE . ' is limited to 10 set or remove elements');
}
}
private function preloadCollection(PropFind $propFind, ICollection $collection): void {
if (!$collection instanceof CalendarHome || $propFind->getDepth() !== 1) {
return;
}
$backend = $collection->getCalDAVBackend();
if (!$backend instanceof CalDavBackend) {
return;
}
$calendars = $collection->getChildren();View on GitHub (pinned to ecdeb153ff)
Solutions
- Skip the POST entirely when the computed set/remove diff is empty
- Include at least one set or remove element (each with a DAV: href) in the body
- When unsharing all sharees, enumerate current invitees and emit one remove element per sharee
Example fix
// before: empty operation list -> 400 <x1:share xmlns:x1='http://owncloud.org/ns'></x1:share> // after: at least one set or remove element <x1:share xmlns:x1='http://owncloud.org/ns' xmlns:d='DAV:'> <x1:remove><d:href>principal:principals/users/bob</d:href></x1:remove> </x1:share>
Defensive patterns
Strategy: validation
Validate before calling
// never send an empty operation list
function buildShareBody(setList, removeList) {
if (setList.length + removeList.length === 0) return null; // skip the POST
return shareXml({ set: setList, remove: removeList });
} Prevention
- Compute the set/remove diff first and short-circuit on empty
- Log the outgoing body when a 400 arrives to confirm which guard fired
When it happens
Trigger: POSTing an <oc:share> body with no child elements, or whose children deserialize into empty set/remove arrays — typical when 'unshare everyone' code computes the remove list dynamically and it ends up empty but still sends the POST.
Common situations: Diff-based sync clients that POST the result of an empty diff; UI code that always fires the share request even when the user confirmed no changes; XML with children in an unrecognized namespace so sabre maps none of them into set/remove.
Related errors
- The given request is not valid
- {http://owncloud.org/ns}share is limited to 10 set or remove
- The {http://nextcloud.com/ns}comp-filter requires a valid na
- The {http://nextcloud.com/ns}limit has illegal value
- The {http://nextcloud.com/ns}offset has illegal value
AI-assisted analysis of nextcloud/server@ecdeb153ff (2026-08-17).
Data as JSON: /api/errors/114e360412ccd8d6.
Report an issue: GitHub.