{"record":{"id":"002b2627b6ee0968","repo":"nextcloud/server","slug":"access-denied","errorCode":null,"errorMessage":"Access denied","messagePattern":"Access denied","errorType":"exception","errorClass":"Sabre\\DAV\\Exception\\Forbidden","httpStatus":403,"severity":"error","filePath":"apps/dav/lib/Connector/Sabre/DavAclPlugin.php","lineNumber":57,"sourceCode":"\t\tif ($access === false && $throwExceptions) {\n\t\t\t/** @var INode $node */\n\t\t\t$node = $this->server->tree->getNodeForPath($uri);\n\n\t\t\tswitch (get_class($node)) {\n\t\t\t\tcase AddressBook::class:\n\t\t\t\t\t$type = 'Addressbook';\n\t\t\t\t\tbreak;\n\t\t\t\tcase Calendar::class:\n\t\t\t\tcase CachedSubscription::class:\n\t\t\t\t\t$type = 'Calendar';\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\t$type = 'Node';\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif ($this->getCurrentUserPrincipal() === $node->getOwner()) {\n\t\t\t\tthrow new Forbidden('Access denied');\n\t\t\t} else {\n\t\t\t\tthrow new NotFound(\n\t\t\t\t\tsprintf(\n\t\t\t\t\t\t\"%s with name '%s' could not be found\",\n\t\t\t\t\t\t$type,\n\t\t\t\t\t\t$node->getName()\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t}\n\n\t\t}\n\n\t\treturn $access;\n\t}\n\n\t#[\\Override]\n\tpublic function propFind(PropFind $propFind, INode $node) {\n\t\tif ($node instanceof Node) {","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/nextcloud/server/blob/ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3/apps/dav/lib/Connector/Sabre/DavAclPlugin.php#L39-L75","documentation":"During the DAV ACL pre-flight check, access to the node was denied. When the current principal equals the node's owner, DavAclPlugin answers Forbidden('Access denied') (HTTP 403); for everyone else it masks the denial as 404. An owner-side 403 here typically means a policy layer such as files_accesscontrol denied the owner access to their own node.","triggerScenarios":"PROPFIND/GET on a calendar, addressbook, or file node whose getOwner() equals the current principal while the access check fails — e.g. a files_accesscontrol workflow rule matching the path, tag, or user.","commonSituations":"Compliance/workflow rules blocking owners from their own resources; debugging with an account that owns many nodes; permission-affecting app updates changing access check outcomes.","solutions":["Check files_accesscontrol/workflow rules and whether their matchers hit this path or user.","Verify the node's actual owner matches the principal you authenticate with (calendars: occ dav:list-calendars; files: file owner metadata).","Temporarily disable the suspect rule to confirm it is the source, then narrow its matchers."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    $client->propfind($resourceUrl, []);\n} catch (Forbidden $e) { // HTTP 403: you own it but a rule denies access\n    surfaceToUser('A workflow or ACL rule denies access to this resource');\n} catch (NotFound $e) {   // HTTP 404: masked denial or really gone\n    forgetResource($resourceUrl);\n}","preventionTips":["When you own the node and get 403, check workflow/files_accesscontrol rules first.","Log the node class involved — it identifies which app imposed the restriction.","Review rule matchers after permission-affecting app updates."],"tags":["dav","acl","workflow","files-accesscontrol","forbidden"],"backgroundTag":"permission-denied","analyzedSha":"ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3","analyzedAt":"2026-08-17T01:36:13.386Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}