nextcloud/server · error · Forbidden

Permission denied to delete the trashbin

Error message

Permission denied to delete the trashbin

What it means

TrashbinHome::delete() throws Sabre\DAV\Exception\Forbidden unconditionally: the CalDAV trashbin collection itself can never be removed via DAV. A DELETE aimed at /remote.php/dav/calendars/<user>/trashbin always yields HTTP 403, even though the owner's ACL grants {DAV:}all on the node - the privilege only covers operations the node actually supports.

Source

Thrown at apps/dav/lib/CalDAV/Trashbin/TrashbinHome.php:109

			new RestoreTarget(),
			new DeletedCalendarObjectsCollection(
				$this->caldavBackend,
				$this->principalInfo
			),
		];
	}

	#[\Override]
	public function childExists($name): bool {
		return in_array($name, [
			RestoreTarget::NAME,
			DeletedCalendarObjectsCollection::NAME,
		], true);
	}

	#[\Override]
	public function delete() {
		throw new Forbidden('Permission denied to delete the trashbin');
	}

	#[\Override]
	public function getName(): string {
		return self::NAME;
	}

	#[\Override]
	public function setName($name) {
		throw new Forbidden('Permission denied to rename the trashbin');
	}

	#[\Override]
	public function getLastModified(): int {
		return 0;
	}

	#[\Override]

View on GitHub (pinned to ecdeb153ff)

Solutions

  1. Do not DELETE the trashbin root; it is a permanent per-principal system collection
  2. Remove deleted items individually under trashbin/objects/ instead
  3. Filter the trashbin out of any recursive delete/cleanup logic

Example fix

// before
DELETE /remote.php/dav/calendars/alice/trashbin
-> 403 Permission denied to delete the trashbin

// after
DELETE /remote.php/dav/calendars/alice/trashbin/objects/old-event.ics
Defensive patterns

Strategy: validation

Validate before calling

if (rtrim($deleteTarget, '/') === "/remote.php/dav/calendars/{$user}/trashbin") {
    return; // never DELETE the trashbin collection itself
}

Try / catch

try {
    $client->request('DELETE', $uri);
} catch (\Sabre\HTTP\ClientHttpException $e) {
    if ($e->getResponse()->getStatus() === 403 && str_ends_with(rtrim($uri, '/'), '/trashbin')) {
        return; // permanent system collection: skip
    }
    throw $e;
}

Prevention

When it happens

Trigger: DELETE /remote.php/dav/calendars/<user>/trashbin; an 'empty all' client feature that walks every discovered collection including the trashbin; cleanup scripts recursing over the whole DAV tree.

Common situations: Users clicking 'delete' on the trashbin node shown in a client's tree view; migration or cleanup tooling that issues DELETE to every collection it finds.

Related errors


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