{"record":{"id":"b2217343984442cf","repo":"nextcloud/server","slug":"vcard-object-exceeds-cardsizelimit-bytes","errorCode":null,"errorMessage":"VCard object exceeds $cardSizeLimit bytes","messagePattern":"VCard object exceeds \\$cardSizeLimit bytes","errorType":"http","errorClass":"Sabre\\DAV\\Exception\\Forbidden","httpStatus":403,"severity":"error","filePath":"apps/dav/lib/CardDAV/Validation/CardDavValidatePlugin.php","lineNumber":36,"sourceCode":"use Sabre\\HTTP\\ResponseInterface;\n\nclass CardDavValidatePlugin extends ServerPlugin {\n\n\tpublic function __construct(\n\t\tprivate IAppConfig $config,\n\t) {\n\t}\n\n\t#[\\Override]\n\tpublic function initialize(Server $server): void {\n\t\t$server->on('beforeMethod:PUT', [$this, 'beforePut']);\n\t}\n\n\tpublic function beforePut(RequestInterface $request, ResponseInterface $response): bool {\n\t\t// evaluate if card size exceeds defined limit\n\t\t$cardSizeLimit = $this->config->getValueInt(Application::APP_ID, 'card_size_limit', 5242880);\n\t\tif ((int)$request->getRawServerValue('CONTENT_LENGTH') > $cardSizeLimit) {\n\t\t\tthrow new Forbidden(\"VCard object exceeds $cardSizeLimit bytes\");\n\t\t}\n\t\t// all tests passed return true\n\t\treturn true;\n\t}\n\n}\n","sourceCodeStart":18,"sourceCodeEnd":43,"githubUrl":"https://github.com/nextcloud/server/blob/ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3/apps/dav/lib/CardDAV/Validation/CardDavValidatePlugin.php#L18-L43","documentation":"Sabre\\DAV\\Exception\\Forbidden thrown by CardDavValidatePlugin::beforePut (apps/dav/lib/CardDAV/Validation/CardDavValidatePlugin.php:36). The DAV server enforces a per-vCard size ceiling on PUT, read from the request CONTENT_LENGTH header and compared against the app config value 'card_size_limit' (default 5242880 bytes = 5 MiB). Oversized cards are rejected before parsing.","triggerScenarios":"PUT to a card resource (e.g. /remote.php/dav/addressbooks/users/<uid>/<book>/<card>.vcf) where Content-Length exceeds occ config:app:get dav card_size_limit (default 5 MiB). Typically cards carrying a base64 PHOTO or a huge NOTE field.","commonSituations":"Contacts with high-resolution photos synced from Android/iOS; vCard 3.0 with inline images (no CARD:PHOTO-URI); admins who lowered card_size_limit; migrations importing enriched contact data.","solutions":["Shrink the payload - downscale/remove the embedded PHOTO or trim oversized fields, then re-PUT","Check the current limit with occ config:app:get dav card_size_limit and raise it if your data legitimately needs more (occ config:app:set dav card_size_limit --value 10485760)","If raising the limit, also check webserver/PHP upload limits (client_max_body_size, upload_max_filesize, post_max_size) so the request is not cut off earlier"],"exampleFix":"# before\nocc config:app:get dav card_size_limit   # 5242880 -> 5 MB cards rejected\n# after (server side, when bigger cards are wanted)\nocc config:app:set dav card_size_limit --value 10485760\n\n// client side: strip the embedded photo before PUT\nif (isset($vcard->PHOTO)) { unset($vcard->PHOTO); }","handlingStrategy":"validation","validationCode":"// client-side: check payload size before PUT\nconst MAX = 5 * 1024 * 1024; // keep in sync with dav card_size_limit\nconst card = vcard.toString();\nif (Buffer.byteLength(card) > MAX) {\n    stripPhotoOrFail(vcard, MAX);\n}","typeGuard":null,"tryCatchPattern":"try {\n    await client.putCard(card);\n} catch (e) {\n    if (e.status === 403 && /exceeds \\d+ bytes/.test(e.message)) {\n        await shrinkCard(vcard); // remove PHOTO / large fields, then retry once\n    }\n}","preventionTips":["Downscale contact photos before embedding them in vcards","Prefer PHOTO-URI over inline base64 photos when the client allows","Keep the client limit in sync with occ config:app:get dav card_size_limit"],"tags":["carddav","dav","put","size-limit","forbidden","http-403","vcard","content-length"],"backgroundTag":"request-body-too-large","analyzedSha":"ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3","analyzedAt":"2026-08-17T01:36:13.386Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}