nextcloud/server · warning · Forbidden
Permission denied to create files in the trashbin
Error message
Permission denied to create files in the trashbin
What it means
TrashbinHome is the 'trashbin' collection at calendars/<principal>/trashbin/. Its createFile() unconditionally throws this Forbidden (HTTP 403): files cannot be created directly in the trashbin root. The trashbin only has the fixed children 'restore' (RestoreTarget) and 'objects' (DeletedCalendarObjectsCollection), and its content is produced exclusively by the server when calendar objects are deleted.
Source
Thrown at apps/dav/lib/CalDAV/Trashbin/TrashbinHome.php:65
'principal' => $ownerPrincipal,
'protected' => true,
],
[
'privilege' => '{DAV:}all',
'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
);
}View on GitHub (pinned to ecdeb153ff)
Solutions
- Never PUT to calendars/<user>/trashbin/ or its children; write new events into the target calendar collection (calendars/<user>/<calendar>/<uri>.ics) instead
- Make clients treat the trashbin subtree (trashbin, trashbin/objects, trashbin/restore) as read-only system state
- In tests, populate the trashbin by deleting a real calendar object rather than uploading
Example fix
# before: upload into the trashbin root (403) PUT /remote.php/dav/calendars/alice/trashbin/event.ics # after: upload into the calendar; delete it afterwards if trashbin state is needed PUT /remote.php/dav/calendars/alice/personal/event.ics DELETE /remote.php/dav/calendars/alice/personal/event.ics
Defensive patterns
Strategy: validation
Validate before calling
const isTrashbinRoot = (href) => /\/trashbin\/?$/.test(href) || href.includes('/trashbin/');
if (!isTrashbinRoot(destHref)) {
await client.put(destHref, icalData);
} Type guard
function isTrashbinHref(href: string): boolean {
return href.includes('/trashbin');
} Prevention
- Allow writes only to calendar collections identified via PROPFIND resourcetype
- Keep one shared path guard that blocks PUT/MKCOL for the whole trashbin subtree
- Populate trashbins in tests by deleting live objects, never by uploading
When it happens
Trigger: A PUT to /remote.php/dav/calendars/<principal>/trashbin/<filename> attempting to upload into the trashbin root; clients resolving a 404 for an unknown trashbin child by trying to create it.
Common situations: File-manager style clients treating the trashbin as a writable folder; sync tools uploading a full local tree including special folders; automated tests probing writability of system collections.
Related errors
- This calendar-object is read-only
- Read-only sharees cannot permanently delete trashbin entries
- Read-only sharees cannot restore trashbin entries
- Permission denied to create a directory in the trashbin
- Permission denied to delete the trashbin
AI-assisted analysis of nextcloud/server@ecdeb153ff (2026-08-17).
Data as JSON: /api/errors/b4d0d70e7ba4b4bc.
Report an issue: GitHub.