{"record":{"id":"f0a7f9787c3a8e33","repo":"nextcloud/server","slug":"creating-collections-in-address-book-objects-is-no","errorCode":null,"errorMessage":"Creating collections in address book objects is not allowed","messagePattern":"Creating collections in address book objects is not allowed","errorType":"http","errorClass":"Sabre\\DAV\\Exception\\MethodNotAllowed","httpStatus":405,"severity":"warning","filePath":"apps/dav/lib/CardDAV/Integration/ExternalAddressBook.php","lineNumber":67,"sourceCode":"\t\t\t$this->appId,\n\t\t\t$this->uri,\n\t\t]);\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t#[\\Override]\n\tfinal public function setName($name) {\n\t\tthrow new DAV\\Exception\\MethodNotAllowed('Renaming address books is not yet supported');\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t#[\\Override]\n\tfinal public function createDirectory($name) {\n\t\tthrow new DAV\\Exception\\MethodNotAllowed('Creating collections in address book objects is not allowed');\n\t}\n\n\t/**\n\t * Checks whether the address book uri is app-generated\n\t *\n\t * @param string $uri\n\t *\n\t * @return bool\n\t */\n\tpublic static function isAppGeneratedAddressBook(string $uri): bool {\n\t\treturn str_starts_with($uri, self::PREFIX) && substr_count($uri, self::DELIMITER) >= 2;\n\t}\n\n\t/**\n\t * Splits an app-generated uri into appId and uri\n\t *\n\t * @param string $uri\n\t *","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/nextcloud/server/blob/ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3/apps/dav/lib/CardDAV/Integration/ExternalAddressBook.php#L49-L85","documentation":"HTTP 405 MethodNotAllowed from the final ExternalAddressBook::createDirectory(). Sabre calls createDirectory() on MKCOL targeting a child under the address book collection; app-generated external address books cannot contain child collections, so the request is always rejected.","triggerScenarios":"MKCOL against /remote.php/dav/addressbooks/<user>/app-generated--<appId>--<uri>/<child>/ by a client that creates sub-collections during sync or provisioning.","commonSituations":"Contact sync clients mirroring local folder trees into DAV; scripts that MKCOL defensively before writing vCards.","solutions":["Create regular address books with MKCOL on the address book home (/remote.php/dav/addressbooks/<user>/)","Skip MKCOL under any address book whose URI starts with app-generated--","Use occ dav:create-address-book for scripted creation"],"exampleFix":"// before: MKCOL under an external address book -> 405\nawait mkcol(`/remote.php/dav/addressbooks/${uid}/app-generated--myapp--team/extra/`);\n// after: create collections only on the address book home\nif (!bookUri.startsWith('app-generated--')) {\n  await mkcol(`/remote.php/dav/addressbooks/${uid}/${newUri}/`);\n}","handlingStrategy":"validation","validationCode":"// client: never MKCOL under an external address book\nfunction assertMkcolTarget(parentBookUri) {\n  if (parentBookUri.startsWith('app-generated--')) {\n    throw new Error('external address books do not accept sub-collections');\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Create address books only on the address book home (/addressbooks/<user>/)","Use occ dav:create-address-book for scripted creation"],"tags":["carddav","external-addressbook","method-not-allowed","mkcol","app-integration"],"backgroundTag":"unsupported-operation","analyzedSha":"ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3","analyzedAt":"2026-08-17T01:36:13.386Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}