toeverything/AFFiNE · error · DocActionDenied
doc_action_denied
doc_action_denied
Error message
You do not have permission to perform ${action} action on doc ${docId}. What it means
Thrown by assertCanReadPublicDoc when the access-control check ac.user(userId).doc(workspaceId, docId).can('Doc.Read') returns false. It guards public/shared document reads (published docs, shared links) so a user without read permission cannot fetch the doc binary or metadata.
Source
Thrown at packages/backend/server/src/core/workspaces/controller.ts:65
private buildVisitorId(req: Request, workspaceId: string, docId: string) {
const tracker = getRequestTrackerId(req);
return createHash('sha256')
.update(`${workspaceId}:${docId}:${tracker}`)
.digest('hex');
}
private async assertCanReadPublicDoc(
userId: string,
workspaceId: string,
docId: string
) {
const canReadSharedDoc = await this.ac
.user(userId)
.doc(workspaceId, docId)
.can('Doc.Read');
if (!canReadSharedDoc) {
throw new DocActionDenied({
docId,
spaceId: workspaceId,
action: 'Doc.Read',
});
}
}
private async getPublishModeHeader(workspaceId: string, docId: string) {
const docMeta = await this.models.doc.getMeta(workspaceId, docId, {
select: {
mode: true,
},
});
return docMeta?.mode === PublicDocMode.Edgeless
? DocMode.edgeless
: DocMode.page;
}
View on GitHub (pinned to 26c515e050)
Solutions
- Verify the doc is published/shared and that the requesting user is the intended recipient.
- Re-share the doc with the user or re-publish it.
- Confirm the correct user identity/session is being sent (CurrentUser).
- Check the access-control rules and role assignments for the workspace/doc.
Example fix
// before
const can = await ac.user(userId).doc(ws, docId).can('Doc.Read')
if (!can) proceed() // ignores denial
// after
const can = await ac.user(userId).doc(ws, docId).can('Doc.Read')
if (!can) throw new Forbidden('ask the owner to share this doc') Defensive patterns
Strategy: validation
Validate before calling
const canRead = await ac.user(userId).doc(workspaceId, docId).can('Doc.Read')
if (!canRead) return showShareRequestUI(workspaceId, docId) Try / catch
try { await fetchPublicDoc(ws, docId) } catch (e) {
if (e.code === 'doc_action_denied') requestAccess(ws, docId)
else throw e
} Prevention
- Check Doc.Read before navigating users into a shared doc.
- Surface a 'request access' flow on denial.
- Audit share/public doc toggles in the UI.
When it happens
Trigger: A request to read a doc (public doc endpoint, shared link) by a user who lacks Doc.Read on that doc: the doc is not actually published/shared, the share was revoked, or the wrong user identity is being passed.
Common situations: A shared link was expired/revoked; a public doc switched back to private; the wrong userId is passed (anonymous vs authenticated); permission propagation lag after a role change.
Related errors
AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12).
Data as JSON: /api/errors/907b1016104fa276.
Report an issue: GitHub.