nextcloud / nextcloud/groupfolders
File creation (PUT) fails with 403 Forbidden in Team folders while folder creation (MKCOL) succeeds
Nobody has claimed this yet.
- Dominant language
- PHP
- Stars
- 343
- Forks
- 106
- Avg merge
- 2d 3h
- Merged PRs (30d)
- 34
Description
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 viaocc 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
PUTa small text file directly at the root of the Team folder via WebDAV (/remote.php/dav/files/<user>/<TeamFolder>/test.txt) - Attempt
MKCOLat the same location for comparison
Expected 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, 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_acltable 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) 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.- Filesystem:
www-datacan write directly to the underlying directory on disk (confirmed via directecho/catinside the app container) — not a filesystem/NFS permission issue. - Redis
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.- 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.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with apps/dav/lib/Connector/Sabre/Directory.php:107 and compare createFile()'s fileView->isCreatable() check with createDirectory()'s info->isCreatable() path. Run the reported curl PUT and MKCOL reproduction against a fresh Team folder. Done means uploads return 201 in Team folders while folder creation continues to work.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- php
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100