{"record":{"id":"57cabb7c0eeec921","repo":"nextcloud/server","slug":"uri-too-long-address-book-not-created","errorCode":null,"errorMessage":"URI too long. Address book not created","messagePattern":"URI too long\\. Address book not created","errorType":"exception","errorClass":"BadRequest","httpStatus":400,"severity":"error","filePath":"apps/dav/lib/CardDAV/CardDavBackend.php","lineNumber":361,"sourceCode":"\n\t\t\treturn true;\n\t\t});\n\t}\n\n\t/**\n\t * Creates a new address book\n\t *\n\t * @param string $principalUri\n\t * @param string $url Just the 'basename' of the url.\n\t * @param array $properties\n\t * @return int\n\t * @throws BadRequest\n\t * @throws Exception\n\t */\n\t#[\\Override]\n\tpublic function createAddressBook($principalUri, $url, array $properties) {\n\t\tif (strlen($url) > 255) {\n\t\t\tthrow new BadRequest('URI too long. Address book not created');\n\t\t}\n\n\t\t$values = [\n\t\t\t'displayname' => null,\n\t\t\t'description' => null,\n\t\t\t'principaluri' => $principalUri,\n\t\t\t'uri' => $url,\n\t\t\t'synctoken' => 1\n\t\t];\n\n\t\tforeach ($properties as $property => $newValue) {\n\t\t\tswitch ($property) {\n\t\t\t\tcase '{DAV:}displayname':\n\t\t\t\t\t$values['displayname'] = $newValue;\n\t\t\t\t\tbreak;\n\t\t\t\tcase '{' . Plugin::NS_CARDDAV . '}addressbook-description':\n\t\t\t\t\t$values['description'] = $newValue;\n\t\t\t\t\tbreak;","sourceCodeStart":343,"sourceCodeEnd":379,"githubUrl":"https://github.com/nextcloud/server/blob/ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3/apps/dav/lib/CardDAV/CardDavBackend.php#L343-L379","documentation":"CardDavBackend::createAddressBook() validates the URI segment before insert: strlen($url) > 255 throws BadRequest('URI too long. Address book not created') (HTTP 400). The cap protects the oc_addressbooks.uri column (VARCHAR(255)) and URL routing. It applies to the collection URI segment, not to the display name.","triggerScenarios":"MKCOL under /addressbooks/users/<user>/ whose collection name exceeds 255 bytes; importers deriving the URI verbatim from a long display name; UTF-8 names that percent-encode past 255 bytes.","commonSituations":"Bulk imports of addressbooks named after org units or long descriptions; URI schemes that concatenate title plus UUID; test generators with random long strings.","solutions":["Generate a short URI (slug, hash, UUID) and carry the full name in {DAV:}displayname","Check strlen($uri) <= 255 client-side before MKCOL","When importing long-named books, map them to short ids like book-<n>"],"exampleFix":"// before\n$uri = 'sales-emea-region-q3-merged-master-list-extended-edition-2026-final-version';\n$backend->createAddressBook('principals/users/alice', $uri, $props); // 400 URI too long\n\n// after\n$uri = 'contacts-' . substr(sha1($name), 0, 8);\n$backend->createAddressBook('principals/users/alice', $uri, ['{DAV:}displayname' => $name]);","handlingStrategy":"validation","validationCode":"if (strlen($uri) > 255) {\n    $uri = 'book-' . substr(sha1($uri), 0, 12); // keep the full name in displayname\n}","typeGuard":"function isValidAddressBookUri(string $uri): bool\n{\n    return $uri !== '' && strlen($uri) <= 255;\n}","tryCatchPattern":"try {\n    $backend->createAddressBook($principalUri, $uri, $props);\n} catch (\\Sabre\\DAV\\Exception\\BadRequest $e) {\n    if (str_contains($e->getMessage(), 'URI too long')) {\n        $backend->createAddressBook($principalUri, 'book-' . substr(sha1($uri), 0, 12), ['{DAV:}displayname' => $displayName]);\n    }\n}","preventionTips":["Derive addressbook URIs from slugs or ids, never raw display names","Enforce the 255-byte cap client-side, measured on the percent-encoded URI","Put human-readable names in {DAV:}displayname, not the URI segment"],"tags":["carddav","dav","http-400","mkcol","validation"],"backgroundTag":"uri-too-long","analyzedSha":"ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3","analyzedAt":"2026-08-17T01:36:13.386Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}