{"record":{"id":"0c682ecc79294f31","repo":"nextcloud/server","slug":"calendar-limit-reached","errorCode":null,"errorMessage":"Calendar limit reached","messagePattern":"Calendar limit reached","errorType":"exception","errorClass":"Forbidden","httpStatus":403,"severity":"error","filePath":"apps/dav/lib/CalDAV/Security/RateLimitingPlugin.php","lineNumber":80,"sourceCode":"\t\t\t\t);\n\t\t\t} catch (RateLimitExceededException $e) {\n\t\t\t\tthrow new TooManyRequests('Too many calendars created', 0, $e);\n\t\t\t}\n\n\t\t\t$calendarLimit = $this->config->getValueInt('dav', 'maximumCalendarsSubscriptions', 30);\n\t\t\tif ($calendarLimit === -1) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t$numCalendars = $this->calDavBackend->getCalendarsForUserCount('principals/users/' . $user->getUID());\n\t\t\t$numSubscriptions = $this->calDavBackend->getSubscriptionsForUserCount('principals/users/' . $user->getUID());\n\n\t\t\tif (($numCalendars + $numSubscriptions) >= $calendarLimit) {\n\t\t\t\t$this->logger->warning('Maximum number of calendars/subscriptions reached', [\n\t\t\t\t\t'calendars' => $numCalendars,\n\t\t\t\t\t'subscription' => $numSubscriptions,\n\t\t\t\t\t'limit' => $calendarLimit,\n\t\t\t\t]);\n\t\t\t\tthrow new Forbidden('Calendar limit reached', 0);\n\t\t\t}\n\t\t}\n\t}\n\n}\n","sourceCodeStart":62,"sourceCodeEnd":86,"githubUrl":"https://github.com/nextcloud/server/blob/ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3/apps/dav/lib/CalDAV/Security/RateLimitingPlugin.php#L62-L86","documentation":"Also raised in RateLimitingPlugin::beforeBind, but by the hard cap check rather than the time-based limiter: before any calendar or subscription creation it counts the user's calendars (getCalendarsForUserCount) plus subscriptions (getSubscriptionsForUserCount) and, when the sum is already >= maximumCalendarsSubscriptions (default 30, -1 disables the check), throws a Sabre Forbidden (HTTP 403). The server logs a warning with the counts and limit before throwing.","triggerScenarios":"Creating another calendar (MKCALENDAR on calendars/<user>/<name>) or a webcal subscription when the user already owns 30 or more calendars plus subscriptions combined; the rate-limit check passes first, then this absolute cap rejects the request.","commonSituations":"Long-lived accounts accumulating webcal subscriptions (subscriptions count toward the same cap); teams that lowered maximumCalendarsSubscriptions; import scripts assuming unlimited calendars; confusion because deleting only calendars while many subscriptions exist still trips the limit.","solutions":["Delete or unsubscribe unused calendars/subscriptions to get below the cap (PROPFIND the calendar home to audit what exists)","Raise the cap: occ config:app:set dav maximumCalendarsSubscriptions --value 100","Set -1 to disable the cap entirely if the instance must allow unlimited calendars","In client UIs, surface the limit clearly so users prune instead of retrying"],"exampleFix":"# before: default cap of 30\nocc config:app:get dav maximumCalendarsSubscriptions\n# (empty / 30)\n\n# after: raise the cap\nocc config:app:set dav maximumCalendarsSubscriptions --value 100","handlingStrategy":"validation","validationCode":"# Count existing calendars+subscriptions before creating another\nPROPFIND /remote.php/dav/calendars/alice/  (Depth: 1)\n# -> count <d:response> entries with resourcetype calendar or subscription;\n#    only issue MKCALENDAR when count < maximumCalendarsSubscriptions (default 30)","typeGuard":null,"tryCatchPattern":"try {\n    await client.mkCalendar(url);\n} catch (e) {\n    if (e.status === 403 && /Calendar limit reached/.test(e.message)) {\n        // guide the user to delete calendars/subscriptions or raise the cap\n        return promptUserToFreezeOrRaiseLimit();\n    }\n    throw e;\n}","preventionTips":["Cache the calendar count per user and warn before hitting the cap","Remember webcal subscriptions count toward maximumCalendarsSubscriptions","Expose the configured cap in admin tooling and monitor the 'Maximum number of calendars/subscriptions reached' server log warning"],"tags":["caldav","dav","quota","limit","http-403","nextcloud"],"backgroundTag":"quota-exceeded","analyzedSha":"ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3","analyzedAt":"2026-08-17T01:36:13.386Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}