nextcloud/server · error · Sabre\DAV\Exception\Forbidden

VCard object exceeds $cardSizeLimit bytes

Error message

VCard object exceeds $cardSizeLimit bytes

What it means

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.

Source

Thrown at apps/dav/lib/CardDAV/Validation/CardDavValidatePlugin.php:36

use Sabre\HTTP\ResponseInterface;

class CardDavValidatePlugin extends ServerPlugin {

	public function __construct(
		private IAppConfig $config,
	) {
	}

	#[\Override]
	public function initialize(Server $server): void {
		$server->on('beforeMethod:PUT', [$this, 'beforePut']);
	}

	public function beforePut(RequestInterface $request, ResponseInterface $response): bool {
		// evaluate if card size exceeds defined limit
		$cardSizeLimit = $this->config->getValueInt(Application::APP_ID, 'card_size_limit', 5242880);
		if ((int)$request->getRawServerValue('CONTENT_LENGTH') > $cardSizeLimit) {
			throw new Forbidden("VCard object exceeds $cardSizeLimit bytes");
		}
		// all tests passed return true
		return true;
	}

}

View on GitHub (pinned to ecdeb153ff)

Solutions

  1. Shrink the payload - downscale/remove the embedded PHOTO or trim oversized fields, then re-PUT
  2. 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)
  3. 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

Example fix

# before
occ config:app:get dav card_size_limit   # 5242880 -> 5 MB cards rejected
# after (server side, when bigger cards are wanted)
occ config:app:set dav card_size_limit --value 10485760

// client side: strip the embedded photo before PUT
if (isset($vcard->PHOTO)) { unset($vcard->PHOTO); }
Defensive patterns

Strategy: validation

Validate before calling

// client-side: check payload size before PUT
const MAX = 5 * 1024 * 1024; // keep in sync with dav card_size_limit
const card = vcard.toString();
if (Buffer.byteLength(card) > MAX) {
    stripPhotoOrFail(vcard, MAX);
}

Try / catch

try {
    await client.putCard(card);
} catch (e) {
    if (e.status === 403 && /exceeds \d+ bytes/.test(e.message)) {
        await shrinkCard(vcard); // remove PHOTO / large fields, then retry once
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of nextcloud/server@ecdeb153ff (2026-08-17). Data as JSON: /api/errors/b2217343984442cf. Report an issue: GitHub.