{"record":{"id":"e529cbb8c97fd8c7","repo":"nextcloud/server","slug":"the-resource-you-tried-to-create-has-a-reserved-na-e529cb","errorCode":null,"errorMessage":"The resource you tried to create has a reserved name","messagePattern":"The resource you tried to create has a reserved name","errorType":"http","errorClass":"Sabre\\DAV\\Exception\\MethodNotAllowed","httpStatus":405,"severity":"error","filePath":"apps/dav/lib/CardDAV/UserAddressBooks.php","lineNumber":117,"sourceCode":"\t\t\t\t\t\t$this->groupManager\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn new AddressBook($this->carddavBackend, $addressBook, $this->l10n);\n\t\t\t}, $addressBooks);\n\t\t}\n\t\t/** @var IAddressBook[][] $objectsFromPlugins */\n\t\t$objectsFromPlugins = array_map(function (IAddressBookProvider $plugin): array {\n\t\t\treturn $plugin->fetchAllForAddressBookHome($this->principalUri);\n\t\t}, $this->pluginManager->getAddressBookPlugins());\n\n\t\treturn array_merge($objects, ...$objectsFromPlugins);\n\t}\n\n\t#[\\Override]\n\tpublic function createExtendedCollection($name, MkCol $mkCol) {\n\t\tif (ExternalAddressBook::doesViolateReservedName($name)) {\n\t\t\tthrow new MethodNotAllowed('The resource you tried to create has a reserved name');\n\t\t}\n\n\t\tparent::createExtendedCollection($name, $mkCol);\n\t}\n\n\t/**\n\t * Returns a list of ACE's for this node.\n\t *\n\t * Each ACE has the following properties:\n\t *   * 'privilege', a string such as {DAV:}read or {DAV:}write. These are\n\t *     currently the only supported privileges\n\t *   * 'principal', a url to the principal who owns the node\n\t *   * 'protected' (optional), indicating that this ACE is not allowed to\n\t *      be updated.\n\t *\n\t * @return array\n\t */\n\t#[\\Override]","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/nextcloud/server/blob/ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3/apps/dav/lib/CardDAV/UserAddressBooks.php#L99-L135","documentation":"Sabre\\DAV\\Exception\\MethodNotAllowed thrown by UserAddressBooks::createExtendedCollection() (apps/dav/lib/CardDAV/UserAddressBooks.php:117). Names starting with the reserved prefix 'z-app-generated' are set aside for addressbooks provisioned by apps via the CardDAV plugin API (ExternalAddressBook), so MKCOL/MKCOL_EXTENDED with such a name is rejected before the parent creates the collection.","triggerScenarios":"An MKCOL or extended MKCOL (addressbook creation) request on /remote.php/dav/addressbooks/users/<uid>/ whose display name or URI begins with 'z-app-generated' (e.g. 'z-app-generated--deck-123'). Same rejection applies in CalendarHome for calendars via the analogous ExternalCalendar::doesViolateReservedName().","commonSituations":"A client that copies an app-generated addressbook URI from one server to another and tries to recreate it; admin import/sync scripts that replay URIs observed via PROPFIND; custom apps that picked a URI prefix colliding with the reserved one.","solutions":["Pick any name that does not start with 'z-app-generated' (e.g. 'personal', 'work') for user-created addressbooks","If you are writing an app that provisions addressbooks, register an IAddressBookProvider plugin instead of MKCOL - the reserved namespace is exactly what identifies plugin books","Strip or rename the prefix when importing/migrating data from another instance"],"exampleFix":"// before\n$client->request('MKCOL', '/remote.php/dav/addressbooks/users/alice/z-app-generated--myapp-1', $body);\n// after\n$client->request('MKCOL', '/remote.php/dav/addressbooks/users/alice/my-app-book', $body);","handlingStrategy":"validation","validationCode":"// reject reserved names client-side before MKCOL\nconst RESERVED_PREFIX = 'z-app-generated';\nif (name.startsWith(RESERVED_PREFIX)) {\n    throw new Error(`Addressbook name must not start with ${RESERVED_PREFIX}`);\n}","typeGuard":"const isReservedAddressBookName = (name: string): boolean =>\n    name.startsWith('z-app-generated');","tryCatchPattern":"try {\n    await client.createAddressBook(name);\n} catch (e) {\n    if (e.status === 405 && /reserved name/.test(e.message)) {\n        // pick another name; this namespace belongs to app plugins\n    }\n}","preventionTips":["Namespace app provisioned data behind the plugin API, not MKCOL","Validate user-chosen URIs against the reserved prefix client-side","On migration, rewrite any z-app-generated URIs before recreating them"],"tags":["carddav","dav","mkcol","reserved-name","method-not-allowed","http-405"],"backgroundTag":"reserved-resource-name","analyzedSha":"ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3","analyzedAt":"2026-08-17T01:36:13.386Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}