{"record":{"id":"a0d7a8a1de94adeb","repo":"nextcloud/server","slug":"http-owncloud-org-ns-share-is-limited-to-10-set","errorCode":null,"errorMessage":"{http://owncloud.org/ns}share is limited to 10 set or remove elements","messagePattern":"(.+?)share is limited to 10 set or remove elements","errorType":"exception","errorClass":"Sabre\\DAV\\Exception\\BadRequest","httpStatus":400,"severity":"error","filePath":"apps/dav/lib/DAV/Sharing/Plugin.php","lineNumber":188,"sourceCode":"\t\t\t\t// Breaking the event chain\n\t\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate function validateShareRequest($shareRequest): void {\n\t\tif (!$shareRequest instanceof ShareRequest) {\n\t\t\t// @FIXME: Replace switch-case in httpPost with instanceof ShareRequest\n\t\t\tthrow new BadRequest('The given request is not valid');\n\t\t}\n\n\t\t$elements = (count($shareRequest->set) + count($shareRequest->remove));\n\n\t\tif ($elements === 0) {\n\t\t\tthrow new BadRequest(ShareRequest::ELEMENT_SHARE . ' needs at least one set or remove element');\n\t\t}\n\n\t\tif ($elements > 10) {\n\t\t\tthrow new BadRequest(ShareRequest::ELEMENT_SHARE . ' is limited to 10 set or remove elements');\n\t\t}\n\t}\n\n\tprivate function preloadCollection(PropFind $propFind, ICollection $collection): void {\n\t\tif (!$collection instanceof CalendarHome || $propFind->getDepth() !== 1) {\n\t\t\treturn;\n\t\t}\n\n\t\t$backend = $collection->getCalDAVBackend();\n\t\tif (!$backend instanceof CalDavBackend) {\n\t\t\treturn;\n\t\t}\n\n\t\t$calendars = $collection->getChildren();\n\t\t$calendars = array_filter($calendars, static fn (INode $node) => $node instanceof IShareable);\n\t\t/** @var int[] $resourceIds */\n\t\t$resourceIds = array_map(\n\t\t\tstatic fn (IShareable $node) => $node->getResourceId(), $calendars);","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/nextcloud/server/blob/ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3/apps/dav/lib/DAV/Sharing/Plugin.php#L170-L206","documentation":"HTTP 400 BadRequest from validateShareRequest() when a single share POST carries more than 10 set plus remove elements combined. The hard cap of 10 share operations per request protects the share backend from oversized batch updates; it is independent of the per-user rate limit (error 280).","triggerScenarios":"Sharing a calendar or address book with more than 10 users/groups in one <oc:share> body; bulk-migration scripts concatenating all sharees into a single share document.","commonSituations":"Company-wide calendar rollouts scripted in one request; import tools replaying a saved share list; clients without pagination of share operations.","solutions":["Split the sharee list into multiple POSTs of at most 10 set/remove elements each","Cap batch size in your sharing client/library at 10","For very large rollouts, provision shares via occ commands or the OCS Share API instead of CalDAV share POSTs"],"exampleFix":"// before: 25 sharees in one body -> 400 'limited to 10 set or remove elements'\nconst xml = shareXml(allSharees);\nawait davPost(shareUrl, xml);\n// after: chunk into requests of <= 10 elements\nfor (const batch of chunk(allSharees, 10)) {\n  await davPost(shareUrl, shareXml(batch));\n}","handlingStrategy":"validation","validationCode":"const MAX_ELEMENTS_PER_SHARE_POST = 10;\nfunction* shareBatches(operations) {\n  for (let i = 0; i < operations.length; i += MAX_ELEMENTS_PER_SHARE_POST) {\n    yield operations.slice(i, i + MAX_ELEMENTS_PER_SHARE_POST);\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Cap share-operation batches at 10 client-side","Split mixed set+remove lists by total count, not per list"],"tags":["dav","sharing","xml","bad-request","batch-limit"],"backgroundTag":"request-size-limit","analyzedSha":"ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3","analyzedAt":"2026-08-17T01:36:13.386Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}