nextcloud/server · error · Sabre\DAV\Exception\Forbidden

Access denied

Error message

Access denied

What it means

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.

Source

Thrown at apps/dav/lib/Connector/Sabre/DavAclPlugin.php:57

		if ($access === false && $throwExceptions) {
			/** @var INode $node */
			$node = $this->server->tree->getNodeForPath($uri);

			switch (get_class($node)) {
				case AddressBook::class:
					$type = 'Addressbook';
					break;
				case Calendar::class:
				case CachedSubscription::class:
					$type = 'Calendar';
					break;
				default:
					$type = 'Node';
					break;
			}

			if ($this->getCurrentUserPrincipal() === $node->getOwner()) {
				throw new Forbidden('Access denied');
			} else {
				throw new NotFound(
					sprintf(
						"%s with name '%s' could not be found",
						$type,
						$node->getName()
					)
				);
			}

		}

		return $access;
	}

	#[\Override]
	public function propFind(PropFind $propFind, INode $node) {
		if ($node instanceof Node) {

View on GitHub (pinned to ecdeb153ff)

Solutions

  1. Check files_accesscontrol/workflow rules and whether their matchers hit this path or user.
  2. Verify the node's actual owner matches the principal you authenticate with (calendars: occ dav:list-calendars; files: file owner metadata).
  3. Temporarily disable the suspect rule to confirm it is the source, then narrow its matchers.
Defensive patterns

Strategy: try-catch

Try / catch

try {
    $client->propfind($resourceUrl, []);
} catch (Forbidden $e) { // HTTP 403: you own it but a rule denies access
    surfaceToUser('A workflow or ACL rule denies access to this resource');
} catch (NotFound $e) {   // HTTP 404: masked denial or really gone
    forgetResource($resourceUrl);
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Related errors


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