Steps to reproduce
- Create a fresh Team folder:
occ groupfolders:create diag-test-folder
- Assign a group with at least read+create rights:
occ groupfolders:group <folder_id> admin (permission bitmask confirmed via occ groupfolders:list --output=json; reproduced with bitmask 15 R+U+C+D and 7 R+U+C — same result either way)
- Leave Advanced Permissions (ACL) disabled (
"acl":false) and quota unlimited ("quota":-3)
- Attempt to
PUT a small text file directly at the root of the Team folder via WebDAV (/remote.php/dav/files/<user>/<TeamFolder>/test.txt)
- Attempt
MKCOL at the same location for comparison
Expected behaviour
Both operations succeed (201 Created).
Actual behaviour
MKCOL → 201 Created
PUT → 403 Forbidden, empty exception message, reproducible 100% of the time, at the folder root and inside freshly-created subfolders, on every Team folder tested (including one created purely for this diagnosis).
The exception is thrown at apps/dav/lib/Connector/Sabre/Directory.php:107, inside createFile(), at the $this->fileView->isCreatable($this->path) check — see full trace under Nextcloud log below, which also explains why this diverges from the MKCOL code path.
Server configuration
Operating system: Debian (official nextcloud:apache Docker image), running as an LXC container on Proxmox VE
Web server: Apache 2.4.68 (bundled in the nextcloud:apache image)
Database: MariaDB 11 (mariadb:11 Docker image)
PHP version: 8.5.10
Nextcloud version: 34.0.3.2 (see Nextcloud admin page)
Team folders version: 22.0.6 (latest available at time of writing)
Updated from an older Nextcloud/ownCloud or fresh install: Fresh install (2026-09-06), no upgrade path involved
Where did you install Nextcloud from: Official Docker Hub image (nextcloud:apache), via docker-compose
Are you using external storage, if yes which one: No — data directory is a local bind-mount inside the container, backed by an NFS export on the underlying host (not using the "External storage support" app)
Are you using encryption: No (encryption app disabled)
Are you using an external user-backend, if yes which one: No — Database backend, local accounts only (user_ldap disabled)
Client configuration
Browser: N/A — issue originally observed via the Nextcloud Desktop Client (mirall 34.0.3, Windows), then reproduced and isolated directly over WebDAV using curl (bypassing the desktop client entirely) to rule out client-side causes.
Operating system: N/A (server-side reproduction via curl from the Nextcloud host itself)
Logs
Web server error log
Web server error log
No errors in Apache's error output for the failing requests — only the standard combined-format access log line, e.g.:
172.18.0.1 - admin [DATE] "PUT /remote.php/dav/files/admin/diag-test-folder/test.txt HTTP/1.1" 403 182 "-" "curl/8.14.1"
No PHP warnings/errors/notices logged for this request either (checked via `docker logs`, grepped for php|warn|error|notice|fatal).
Nextcloud log (data/nextcloud.log)
Nextcloud log
{"reqId":"IJezfzekFscLn5rzefhM","level":0,"time":"2026-09-13T14:12:30+00:00","remoteAddr":"REDACTED","user":"admin","app":"webdav","method":"PUT","url":"/remote.php/dav/files/admin/Famille/diag-root-test2.txt","scriptName":"/remote.php","message":"Exception thrown: Sabre\\DAV\\Exception\\Forbidden","userAgent":"curl/8.14.1","version":"34.0.3.2","exception":{"Exception":"Sabre\\DAV\\Exception\\Forbidden","Message":"","Code":0,"Trace":[{"file":"/var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php","line":1098,"function":"createFile","class":"OCA\\DAV\\Connector\\Sabre\\Directory","type":"->"},{"file":"/var/www/html/3rdparty/sabre/dav/lib/DAV/CorePlugin.php","line":504,"function":"createFile","class":"Sabre\\DAV\\Server","type":"->"},{"file":"/var/www/html/3rdparty/sabre/event/lib/WildcardEmitterTrait.php","line":89,"function":"httpPut","class":"Sabre\\DAV\\CorePlugin","type":"->"},{"file":"/var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php","line":472,"function":"emit","class":"Sabre\\DAV\\Server","type":"->"},{"file":"/var/www/html/apps/dav/lib/Connector/Sabre/Server.php","line":215,"function":"invokeMethod","class":"Sabre\\DAV\\Server","type":"->"},{"file":"/var/www/html/apps/dav/lib/Server.php","line":433,"function":"start","class":"OCA\\DAV\\Connector\\Sabre\\Server","type":"->"},{"file":"/var/www/html/apps/dav/appinfo/v2/remote.php","line":25,"function":"exec","class":"OCA\\DAV\\Server","type":"->"},{"file":"/var/www/html/remote.php","line":152,"function":"require_once"}],"File":"/var/www/html/apps/dav/lib/Connector/Sabre/Directory.php","Line":107,"CustomMessage":"Exception thrown: Sabre\\DAV\\Exception\\Forbidden"}}
Directory.php:107 corresponds to:
if (!$this->fileView->isCreatable($this->path)) {
throw new \Sabre\DAV\Exception\Forbidden();
}
By contrast, Directory::createDirectory() (used by MKCOL, which succeeds) checks $this->info->isCreatable() — a different code path — which returns true.
Browser log
Browser log
N/A — reproduced directly over WebDAV via curl, no browser involved.
Troubleshooting already performed (ruling out configuration/data issues)
To save maintainers time, the following have all been checked and are not the cause:
occ groupfolders:list --output=json: group permissions bitmask = 15 (Read+Update+Create+Delete) on the original folder, tested again with 7 (R+U+C) on a brand-new folder — same failure either way.
"acl":false, oc_group_folders_acl table empty — Advanced Permissions definitely not in play.
- Quota: originally found at an invalid
-4 (likely leftover from an earlier volume rebuild), corrected to -3 (FileInfo::SPACE_UNLIMITED) via occ groupfolders:quota — no change in behavior.
oc_storages.available = 1 for the Team folder storage — not marked unavailable.
oc_filecache.permissions = 23 for the folder root (includes Create bit) — cache is not the blocker.
- Filesystem:
www-data can write directly to the underlying directory on disk (confirmed via direct echo/cat inside the app container) — not a filesystem/NFS permission issue.
- Redis
FLUSHALL performed, app container fully restarted (clears APCu/opcache) — no change.
occ integrity:check-core and occ integrity:check-app groupfolders both return clean (no output) — app and core files are unmodified/correctly signed.
- Tested on both the original (September-created) folder and a completely fresh Team folder created during this diagnosis — same failure on both, ruling out folder-specific data corruption.
- Personal (non-Team-folder) file uploads to the same user's home storage succeed normally (
201) on the same instance — issue is specific to Team folder storage.
Additional notes
Happy to provide further debug-level logs, run additional occ diagnostics, or test a patch if one is proposed — this is a fully reproducible, minimal-configuration environment.
Steps to reproduce
occ groupfolders:create diag-test-folderocc groupfolders:group <folder_id> admin(permission bitmask confirmed viaocc groupfolders:list --output=json; reproduced with bitmask 15 R+U+C+D and 7 R+U+C — same result either way)"acl":false) and quota unlimited ("quota":-3)PUTa small text file directly at the root of the Team folder via WebDAV (/remote.php/dav/files/<user>/<TeamFolder>/test.txt)MKCOLat the same location for comparisonExpected behaviour
Both operations succeed (
201 Created).Actual behaviour
MKCOL→201 CreatedPUT→403 Forbidden, empty exception message, reproducible 100% of the time, at the folder root and inside freshly-created subfolders, on every Team folder tested (including one created purely for this diagnosis).The exception is thrown at
apps/dav/lib/Connector/Sabre/Directory.php:107, insidecreateFile(), at the$this->fileView->isCreatable($this->path)check — see full trace under Nextcloud log below, which also explains why this diverges from theMKCOLcode path.Server configuration
Operating system: Debian (official
nextcloud:apacheDocker image), running as an LXC container on Proxmox VEWeb server: Apache 2.4.68 (bundled in the
nextcloud:apacheimage)Database: MariaDB 11 (
mariadb:11Docker image)PHP version: 8.5.10
Nextcloud version: 34.0.3.2 (see Nextcloud admin page)
Team folders version: 22.0.6 (latest available at time of writing)
Updated from an older Nextcloud/ownCloud or fresh install: Fresh install (2026-09-06), no upgrade path involved
Where did you install Nextcloud from: Official Docker Hub image (
nextcloud:apache), viadocker-composeAre you using external storage, if yes which one: No — data directory is a local bind-mount inside the container, backed by an NFS export on the underlying host (not using the "External storage support" app)
Are you using encryption: No (
encryptionapp disabled)Are you using an external user-backend, if yes which one: No — Database backend, local accounts only (
user_ldapdisabled)Client configuration
Browser: N/A — issue originally observed via the Nextcloud Desktop Client (mirall 34.0.3, Windows), then reproduced and isolated directly over WebDAV using
curl(bypassing the desktop client entirely) to rule out client-side causes.Operating system: N/A (server-side reproduction via
curlfrom the Nextcloud host itself)Logs
Web server error log
Web server error log
Nextcloud log (data/nextcloud.log)
Nextcloud log
{"reqId":"IJezfzekFscLn5rzefhM","level":0,"time":"2026-09-13T14:12:30+00:00","remoteAddr":"REDACTED","user":"admin","app":"webdav","method":"PUT","url":"/remote.php/dav/files/admin/Famille/diag-root-test2.txt","scriptName":"/remote.php","message":"Exception thrown: Sabre\\DAV\\Exception\\Forbidden","userAgent":"curl/8.14.1","version":"34.0.3.2","exception":{"Exception":"Sabre\\DAV\\Exception\\Forbidden","Message":"","Code":0,"Trace":[{"file":"/var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php","line":1098,"function":"createFile","class":"OCA\\DAV\\Connector\\Sabre\\Directory","type":"->"},{"file":"/var/www/html/3rdparty/sabre/dav/lib/DAV/CorePlugin.php","line":504,"function":"createFile","class":"Sabre\\DAV\\Server","type":"->"},{"file":"/var/www/html/3rdparty/sabre/event/lib/WildcardEmitterTrait.php","line":89,"function":"httpPut","class":"Sabre\\DAV\\CorePlugin","type":"->"},{"file":"/var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php","line":472,"function":"emit","class":"Sabre\\DAV\\Server","type":"->"},{"file":"/var/www/html/apps/dav/lib/Connector/Sabre/Server.php","line":215,"function":"invokeMethod","class":"Sabre\\DAV\\Server","type":"->"},{"file":"/var/www/html/apps/dav/lib/Server.php","line":433,"function":"start","class":"OCA\\DAV\\Connector\\Sabre\\Server","type":"->"},{"file":"/var/www/html/apps/dav/appinfo/v2/remote.php","line":25,"function":"exec","class":"OCA\\DAV\\Server","type":"->"},{"file":"/var/www/html/remote.php","line":152,"function":"require_once"}],"File":"/var/www/html/apps/dav/lib/Connector/Sabre/Directory.php","Line":107,"CustomMessage":"Exception thrown: Sabre\\DAV\\Exception\\Forbidden"}}Directory.php:107corresponds to:By contrast,
Directory::createDirectory()(used byMKCOL, which succeeds) checks$this->info->isCreatable()— a different code path — which returnstrue.Browser log
Browser log
Troubleshooting already performed (ruling out configuration/data issues)
To save maintainers time, the following have all been checked and are not the cause:
occ groupfolders:list --output=json: group permissions bitmask = 15 (Read+Update+Create+Delete) on the original folder, tested again with 7 (R+U+C) on a brand-new folder — same failure either way."acl":false,oc_group_folders_acltable empty — Advanced Permissions definitely not in play.-4(likely leftover from an earlier volume rebuild), corrected to-3(FileInfo::SPACE_UNLIMITED) viaocc groupfolders:quota— no change in behavior.oc_storages.available = 1for the Team folder storage — not marked unavailable.oc_filecache.permissions = 23for the folder root (includes Create bit) — cache is not the blocker.www-datacan write directly to the underlying directory on disk (confirmed via directecho/catinside the app container) — not a filesystem/NFS permission issue.FLUSHALLperformed, app container fully restarted (clears APCu/opcache) — no change.occ integrity:check-coreandocc integrity:check-app groupfoldersboth return clean (no output) — app and core files are unmodified/correctly signed.201) on the same instance — issue is specific to Team folder storage.Additional notes
Happy to provide further debug-level logs, run additional
occdiagnostics, or test a patch if one is proposed — this is a fully reproducible, minimal-configuration environment.