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
- Re-establish or accept the share so the source file is mounted in the recipient's folder
- Have the file owner fetch the version instead of the recipient
- Treat a 404 on a version path as 'no longer shared' and drop the cached entry rather than retrying
- 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
- PROPFIND the shared file first; if it no longer resolves, skip version requests
- Accept pending shares before deep-linking version URLs
- Prefer the owner fetching their own versions
- Drop cached version entries on 404 instead of retrying
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
- Read-only sharees cannot permanently delete trashbin entries
- Entity does not exist or is not available
- Entity type "$name" not found."
- %s with name '%s' could not be found
- Too many addressbook or calendar share requests
AI-assisted analysis of nextcloud/server@ecdeb153ff (2026-08-17).
Data as JSON: /api/errors/99d9775d23b67b86.
Report an issue: GitHub.