nextcloud/server · warning · OCA\DAV\Connector\Sabre\Exception\TooManyRequests

Too many addressbook or calendar share requests

Error message

Too many addressbook or calendar share requests

What it means

HTTP 429 thrown by the DAV rate-limiting helper (OCA\DAV\Connector\Sabre\Exception\TooManyRequests) whenever a logged-in user exceeds the share-operation quota for calendars and address books. The counter is tracked per user under the identifier 'share-addressbook-or-calendar' with defaults of 100 operations per 3600 seconds, read from app config dav/rateLimitShareAddressbookOrCalendar and dav/rateLimitPeriodShareAddressbookOrCalendar. It is enforced in the DAV sharing plugin before every POST whose XML root is an {http://owncloud.org/ns}share document, covering both set (share) and remove (unshare) operations.

Source

Thrown at apps/dav/lib/DAV/Security/RateLimiting.php:43

	}

	/**
	 * @throws TooManyRequests
	 */
	public function check(): void {
		$user = $this->userSession->getUser();
		if ($user === null) {
			return;
		}

		$identifier = 'share-addressbook-or-calendar';
		$userLimit = $this->config->getValueInt('dav', 'rateLimitShareAddressbookOrCalendar', 100);
		$userPeriod = $this->config->getValueInt('dav', 'rateLimitPeriodShareAddressbookOrCalendar', 3600);

		try {
			$this->limiter->registerUserRequest($identifier, $userLimit, $userPeriod, $user);
		} catch (IRateLimitExceededException $e) {
			throw new TooManyRequests('Too many addressbook or calendar share requests', 0, $e);
		}
	}
}

View on GitHub (pinned to ecdeb153ff)

Solutions

  1. Wait for the rate-limit window (default 3600 s) to elapse before issuing more share requests
  2. Batch share changes so one POST carries up to 10 set/remove elements instead of one POST per change
  3. Raise the quota for a known automation account: occ config:app:set dav rateLimitShareAddressbookOrCalendar --value 1000 (and rateLimitPeriodShareAddressbookOrCalendar for the window)
  4. Run bulk provisioning via occ commands (e.g. dav:create-calendar, dav:create-address-book) or the OCS Share API instead of CalDAV share POSTs

Example fix

// before: one POST per sharee -> 150 requests/hour -> HTTP 429
for (const uid of sharees) {
  await davPost(`/remote.php/dav/calendars/${owner}/cal1/`, shareXml([uid]));
}
// after: batch <=10 sharees per request, and raise the quota for migrations
// shell: occ config:app:set dav rateLimitShareAddressbookOrCalendar --value 1000
for (const batch of chunk(sharees, 10)) {
  await davPost(`/remote.php/dav/calendars/${owner}/cal1/`, shareXml(batch));
}
Defensive patterns

Strategy: retry

Validate before calling

// client-side token bucket mirroring the server defaults (100 per 3600 s)
const bucket = { tokens: 100, cap: 100, last: Date.now(), periodMs: 3600_000 };
function canIssueShareRequest() {
  const now = Date.now();
  bucket.tokens = Math.min(bucket.cap, bucket.tokens + ((now - bucket.last) / bucket.periodMs) * bucket.cap);
  bucket.last = now;
  if (bucket.tokens < 1) return false;
  bucket.tokens -= 1;
  return true;
}

Try / catch

try {
  await davPost(calendarUrl, shareXml(batch));
} catch (e) {
  if (e.status === 429) {
    const waitSec = Number(e.headers['retry-after'] ?? 3600);
    await sleep(waitSec * 1000); // one scheduled retry, honoring the window
    return davPost(calendarUrl, shareXml(batch));
  }
  throw e;
}

Prevention

When it happens

Trigger: More than 100 POST requests with Content-Type application/xml and an <oc:share> body against /remote.php/dav/calendars/<user>/<calendar>/ or /remote.php/dav/addressbooks/<user>/<book>/ within one hour by the same user; e.g. a provisioning or sync script that issues one share POST per sharee in a loop.

Common situations: User-management or migration scripts iterating over many users and sharing a calendar/address book with each; CalDAV clients (Thunderbird etc.) re-issuing invites during account setup; CI suites hammering share endpoints; deployments where the 100/hour default was lowered.

Related errors


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