nextcloud/server · error · Forbidden
Permission denied to create a directory in the trashbin
Error message
Permission denied to create a directory in the trashbin
What it means
TrashbinHome is the CalDAV trashbin collection at /remote.php/dav/calendars/<principal>/trashbin. It implements Sabre\DAV\ICollection but is deliberately read-only: deleted-calendar storage cannot be written to directly, and the only valid children are 'restore' and 'objects'. createDirectory() therefore throws Sabre\DAV\Exception\Forbidden unconditionally, which the DAV server maps to HTTP 403 regardless of the caller's ACL privileges.
Source
Thrown at apps/dav/lib/CalDAV/Trashbin/TrashbinHome.php:70
'principal' => $ownerPrincipal . '/calendar-proxy-write',
'protected' => true,
],
[
'privilege' => '{DAV:}read',
'principal' => $ownerPrincipal . '/calendar-proxy-read',
'protected' => true,
],
];
}
#[\Override]
public function createFile($name, $data = null) {
throw new Forbidden('Permission denied to create files in the trashbin');
}
#[\Override]
public function createDirectory($name) {
throw new Forbidden('Permission denied to create a directory in the trashbin');
}
#[\Override]
public function getChild($name): INode {
switch ($name) {
case RestoreTarget::NAME:
return new RestoreTarget();
case DeletedCalendarObjectsCollection::NAME:
return new DeletedCalendarObjectsCollection(
$this->caldavBackend,
$this->principalInfo
);
}
throw new NotFound();
}
#[\Override]View on GitHub (pinned to ecdeb153ff)
Solutions
- Create calendars under the calendar home /remote.php/dav/calendars/<user>/, never under trashbin/
- To undelete, MOVE the object from trashbin/objects/ into trashbin/restore/ instead of creating collections
- Treat 403 on trashbin mutations as expected behavior and do not retry them
Example fix
// before MKCOL /remote.php/dav/calendars/alice/trashbin/holidays/ -> 403 Permission denied to create a directory in the trashbin // after MKCOL /remote.php/dav/calendars/alice/holidays/ -> 201 Created
Defensive patterns
Strategy: validation
Validate before calling
// the trashbin is a read-only sibling of the calendar home
$isTrashbin = str_contains(rtrim($requestUri, '/') . '/', "/remote.php/dav/calendars/{$userId}/trashbin/");
if ($isTrashbin && $method === 'MKCOL') {
throw new LogicException('The CalDAV trashbin is read-only; create calendars under the calendar home');
} Try / catch
try {
$client->request('MKCOL', $uri);
} catch (\Sabre\HTTP\ClientHttpException $e) {
if ($e->getResponse()->getStatus() === 403) {
return; // read-only trashbin: skip, never retry
}
throw $e;
} Prevention
- Only the calendar home (.../calendars/<user>/) accepts MKCOL; the trashbin sibling never does
- Mark collections whose resourcetype contains {http://nextcloud.org/ns}trash-bin as read-only in client UIs
- Never reuse calendar-home URL builders for trashbin paths
When it happens
Trigger: An MKCOL request whose Request-URI is /remote.php/dav/calendars/<user>/trashbin/<name>; a client that discovers the trashbin via PROPFIND and then offers 'new calendar' on it; code that reuses a calendar-home URL builder for the trashbin path.
Common situations: Custom sync or test tooling that blanket-issues MKCOL on every discovered collection; URL mixups between the calendar home (.../calendars/<user>/) and its trashbin sibling (.../calendars/<user>/trashbin/); scripts trying to seed deleted data directly.
Related errors
- Read-only sharees cannot permanently delete trashbin entries
- Permission denied to delete the trashbin
- Permission denied to rename the trashbin
- not implemented
- Calendar limit reached
AI-assisted analysis of nextcloud/server@ecdeb153ff (2026-08-17).
Data as JSON: /api/errors/1416d5741816aaf6.
Report an issue: GitHub.