toeverything/AFFiNE · error · ExpectToUpdateDocUserRole
expect_to_update_doc_user_role
expect_to_update_doc_user_role
Error message
Expect doc not to be workspace
What it means
updateDocUserRole rejects input where workspaceId === docId, continuing the root-is-a-Space guard family. Changing a user's role 'on the workspace root' is not a doc-level operation, so the mutation throws ExpectToUpdateDocUserRole before the Doc.Users.Manage check.
Solutions
- Disable the role-change action for the root node and validate docId !== workspaceId before calling
- Ensure the selected-node id in the UI comes from a page node
- Use workspace member role APIs for workspace-wide changes
Example fix
// before
onRoleChange(node.id /* root node === ws.id */, userId, role);
// after
if (node.id === ws.id) return disableRoleChangeForRoot(node);
await updateDocUserRole({ workspaceId: ws.id, docId: node.id, userId, role }); Defensive patterns
Strategy: validation
Validate before calling
// Guard the update input before calling
if (input.workspaceId === input.docId) {
throw new Error('cannot update a doc role on the workspace root');
}
await updateDocUserRole(input); Type guard
function isExpectToUpdateDocUserRole(e: unknown): boolean {
return (
typeof e === 'object' && e !== null &&
(e as { extensions?: { code?: string } }).extensions?.code === 'expect_to_update_doc_user_role'
);
} Try / catch
try {
await updateDocUserRole(input);
} catch (e) {
if (isExpectToUpdateDocUserRole(e)) {
showSelectAPageError(); // role changes do not apply to the root
} else throw e;
} Prevention
- Disable role-change controls when the selected tree node is the workspace root
- Take docId from the selected page node, never from route defaults
- Share a single isRootGuard(workspaceId, docId) helper across all doc mutation call sites
When it happens
Trigger: Calling updateDocUserRole with input.docId === input.workspaceId — id taken from the wrong object, or a UI whose selected node is the workspace root.
Common situations: Role pickers rendered for the root node of a doc tree; refactors that swapped the argument order or default values.
Related errors
- doc_default_role_can_not_be_owner
- expect_to_grant_doc_user_roles
- expect_to_revoke_doc_user_roles
- expect_to_publish_doc
- expect_to_revoke_public_doc
AI-assisted analysis of toeverything/AFFiNE@2af30773ae (2026-08-18).
Data as JSON: /api/errors/398e56a22968c9d5.
Report an issue: GitHub.
Appendix: source
Thrown at packages/backend/server/src/core/workspaces/resolvers/doc.ts:853
this.logger.log(`Revoke doc user roles (${JSON.stringify(info)})`);
return true;
}
@Mutation(() => Boolean)
async updateDocUserRole(
@CurrentUser() user: CurrentUser,
@Args('input') input: UpdateDocUserRoleInput
): Promise<boolean> {
const pairs = {
spaceId: input.workspaceId,
docId: input.docId,
};
if (input.workspaceId === input.docId) {
this.logger.error(
'Expect to update doc user role, but it is a workspace',
pairs
);
throw new ExpectToUpdateDocUserRole(
pairs,
'Expect doc not to be workspace'
);
}
const info = {
...pairs,
userId: input.userId,
role: input.role,
};
const role = toDomainDocRole(input.role);
if (!role) {
throw new ExpectToUpdateDocUserRole(pairs, 'Invalid doc role');
}
try {
await this.runtime.executeDomainCommandV1({
command: 'transition_doc_role',View on GitHub (pinned to 2af30773ae)