HeyPuter/puter · error · HttpError

permission_denied

permission_denied

Error message

Permission denied

What it means

Thrown by the WebDAV #assertRead helper when ACLService.check(actor, descriptor, 'read') returns false — the authenticated actor lacks read permission on the path (or its nearest resolvable ancestor). Returns 403 Forbidden. Read is required for GET, HEAD, PROPFIND, and the source side of COPY.

Source

Thrown at src/backend/controllers/webdav/WebDAVController.ts:845

        if (lock.path !== davPath)
            throw new HttpError(403, 'Lock token does not match this path', {
                legacyCode: 'forbidden',
            });

        await deleteLock(r, token);
        res.status(204).end();
    }

    // -- ACL helpers -------------------------------------------------

    async #assertRead(actor: Actor, path: string): Promise<void> {
        const descriptor = {
            path,
            resolveAncestors: () => this.services.fs.getAncestorChain(path),
        };
        const ok = await this.services.acl.check(actor, descriptor, 'read');
        if (!ok)
            throw new HttpError(403, 'Permission denied', {
                legacyCode: 'permission_denied',
            });
    }

    async #assertWrite(actor: Actor, path: string): Promise<void> {
        const descriptor = {
            path,
            resolveAncestors: () => this.services.fs.getAncestorChain(path),
        };
        const ok = await this.services.acl.check(actor, descriptor, 'write');
        if (!ok)
            throw new HttpError(403, 'Permission denied', {
                legacyCode: 'permission_denied',
            });
    }

    // -- Event emission ----------------------------------------------

View on GitHub (pinned to 908ec23eda)

Solutions

  1. Authenticate as a user who has been granted read on the path or a parent.
  2. Grant read permission on the path (or a parent) to the actor via the Puter sharing/ACL API.
  3. Verify the basic-auth credentials being sent correspond to the intended user account.
  4. Check the ACL entries on each ancestor up to root to locate where permission is denied.
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check read permission via the Puter ACL/sharing API before the DAV call
const allowed = await puter.fs.stat(path).then(() => true).catch(() => false);
if (!allowed) throw new Error(`No read access to ${path}`);

Try / catch

try {
  await webdavGet(path);
} catch (e) {
  if (e.status === 403) console.error(`Read denied on ${path} — request sharing grant`);
  else throw e;
}

Prevention

When it happens

Trigger: A GET/HEAD/PROPFIND/COPY-source request on a dav.* path whose ACL does not grant the actor's user the read permission. The descriptor resolves ancestors via FSService.getAncestorChain, so denial on any ancestor in the chain triggers it.

Common situations: Accessing another user's shared file without a granted permission; permission revoked between sessions; path under a directory whose ACL was tightened; wrong account authenticated (basic-auth credentials for a different user); newly created entry whose ACL seed omitted the user.

Related errors


AI-assisted analysis of HeyPuter/puter@908ec23eda (2026-08-12). Data as JSON: /api/errors/ee66d72e4b3f00d2. Report an issue: GitHub.