nextcloud/server · error · OCP\Files\NotFoundException

Version file not accessible by current user

Error message

Version file not accessible by current user

What it means

OCP\Files\NotFoundException thrown by ViewOnlyPlugin::checkViewOnly() when a GET/COPY/MOVE hits a versions DAV node whose source file is owned by someone else and the current user's folder contains no node with that file id (userFolder->getFirstNodeById() returns null). Because the surrounding catch only handles Sabre\DAV\Exception\NotFound, this OCP exception propagates to the client as HTTP 404 on the version path.

Source

Thrown at apps/dav/lib/DAV/ViewOnlyPlugin.php:76

	 */
	public function checkViewOnly(RequestInterface $request): bool {
		$path = $request->getPath();

		try {
			assert($this->server !== null);
			$davNode = $this->server->tree->getNodeForPath($path);
			if ($davNode instanceof DavFile) {
				// Restrict view-only to nodes which are shared
				$node = $davNode->getNode();
			} elseif ($davNode instanceof VersionFile) {
				$node = $davNode->getVersion()->getSourceFile();
				$currentUserId = $this->userFolder?->getOwner()?->getUID();
				// The version source file is relative to the owner storage.
				// But we need the node from the current user perspective.
				if ($node->getOwner()->getUID() !== $currentUserId) {
					$node = $this->userFolder->getFirstNodeById($node->getId());
					if ($node === null) {
						throw new NotFoundException('Version file not accessible by current user');
					}
				}
			} else {
				return true;
			}

			$storage = $node->getStorage();
			if (!$storage->instanceOfStorage(ISharedStorage::class)) {
				return true;
			}

			/** @var ISharedStorage $storage */
			$share = $storage->getShare();
			switch ($request->getMethod()) {
				case 'GET':
					// If download is disabled, but viewing is allowed, we still allow the GET method to return the file content.
					if (!$share->canSeeContent()) {
						throw new Forbidden('Access to this shared resource has been denied because its download permission is disabled.');

View on GitHub (pinned to ecdeb153ff)

Solutions

  1. Re-establish or accept the share so the source file is mounted in the recipient's folder
  2. Have the file owner fetch the version instead of the recipient
  3. Treat a 404 on a version path as 'no longer shared' and drop the cached entry rather than retrying
  4. Check the share state (pending/declined/removed) before requesting versions

Example fix

// before: any failure of a version GET is fatal
const content = await davGet(`/remote.php/dav/versions/${owner}/.../${fileId}/${revId}`);
// after: 404 on a shared file's version means 'not accessible for this user'
try {
  const content = await davGet(`/remote.php/dav/versions/${owner}/.../${fileId}/${revId}`);
} catch (e) {
  if (e.status === 404) { dropCachedVersion(fileId, revId); return; }
  throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// resolve the source file in the current user's tree before touching versions
const file = await propfindByFileId(fileId);
if (file === null) {
  // not mounted for this user anymore: share revoked/unaccepted -> skip version fetch
  return;
}

Try / catch

try {
  await davGet(versionPath);
} catch (e) {
  if (e.status === 404) {
    // source file no longer mounted for this user: treat as stale state, not transport error
    removeFromCache(versionPath);
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: A share recipient requests a version under /remote.php/dav/versions/ (or a meta path) for a file that no longer resolves in their own mount tree: the share was deleted, is unaccepted/pending, a group share was revoked, or the file id was never shared to this user.

Common situations: Deep-linked or cached version URLs used after a share was revoked; view-only shares (download disabled) where a client still attempts COPY/MOVE of a version; races between share removal and client synchronization.

Related errors


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