toeverything/AFFiNE · error · DocDefaultRoleCanNotBeOwner

doc_default_role_can_not_be_owner

doc_default_role_can_not_be_owner

Error message

Doc default role can not be owner.

What it means

updateDocDefaultRole refuses role === DocRole.Owner. The default role is what every workspace member effectively gets on the doc; ownership must remain an explicit per-user grant, so making Owner the doc default is rejected with DocDefaultRoleCanNotBeOwner.

Solutions

  1. Choose Admin (or lower) as the default role and filter Owner out of the default-role options
  2. To grant ownership, use grantDocUserRoles for specific users instead of the default role

Example fix

// before
const allRoles = Object.values(DocRole); // includes Owner
await updateDocDefaultRole({ workspaceId, docId, role: 'Owner' }); // -> DOC_DEFAULT_ROLE_CAN_NOT_BE_OWNER

// after
const defaultRoleOptions = Object.values(DocRole).filter(r => r !== 'Owner');
await updateDocDefaultRole({ workspaceId, docId, role: 'Admin' });
Defensive patterns

Strategy: validation

Validate before calling

// Filter Owner out of default-role options before the call
const DEFAULT_ROLE_BLACKLIST = ['Owner'];
function isValidDefaultRole(role: DocRole): boolean {
  return !DEFAULT_ROLE_BLACKLIST.includes(role);
}
if (!isValidDefaultRole(input.role)) {
  throw new Error('default role cannot be Owner');
}
await updateDocDefaultRole(input);

Type guard

function isDefaultRoleOwnerError(e: unknown): boolean {
  return (
    typeof e === 'object' && e !== null &&
    (e as { extensions?: { code?: string } }).extensions?.code === 'doc_default_role_can_not_be_owner'
  );
}

Try / catch

try {
  await updateDocDefaultRole(input);
} catch (e) {
  if (isDefaultRoleOwnerError(e)) {
    input.role = 'Admin'; // nearest valid default; Owner stays a per-user grant
    await updateDocDefaultRole(input);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling updateDocDefaultRole with input.role 'Owner' — typically a UI whose role dropdown lists every DocRole value including Owner, or code copying a member's Owner grant into the default-role field.

Common situations: Role pickers generated straight from the DocRole enum; settings forms that reuse the per-user role list for the default role.

Related errors


AI-assisted analysis of toeverything/AFFiNE@2af30773ae (2026-08-18). Data as JSON: /api/errors/084a06c771b91025. Report an issue: GitHub.

Appendix: source

Thrown at packages/backend/server/src/core/workspaces/resolvers/doc.ts:914

        workspaceId: input.workspaceId,
        docId: input.docId,
      });
      this.logger.log(`Update doc user role (${JSON.stringify(info)})`);
    }

    return true;
  }

  @Mutation(() => Boolean)
  async updateDocDefaultRole(
    @CurrentUser() user: CurrentUser,
    @Args('input') input: UpdateDocDefaultRoleInput
  ) {
    if (input.role === DocRole.Owner) {
      this.logger.debug(
        `Doc default role can not be owner (${JSON.stringify(input)})`
      );
      throw new DocDefaultRoleCanNotBeOwner();
    }
    const pairs = {
      spaceId: input.workspaceId,
      docId: input.docId,
    };
    if (input.workspaceId === input.docId) {
      this.logger.error(
        'Expect to update page default role, but it is a workspace',
        pairs
      );
      throw new ExpectToUpdateDocUserRole(
        pairs,
        'Expect doc not to be workspace'
      );
    }
    const newRole =
      input.role === DocRole.None ? 'none' : toDomainDocRole(input.role);
    if (!newRole) {

View on GitHub (pinned to 2af30773ae)