hasura/graphql-engine · error · DuplicateRootFieldError

Cannot add mutation root field {0} as it already in use

Error message

Cannot add mutation root field {0} as it already in use

What it means

DuplicateRootFieldError::Mutation: the same situation as the Query variant but for the Mutation root type — two metadata entries attempt to register a GraphQL mutation root field with an identical name.

Source

Thrown at v3/crates/metadata-resolve/src/helpers/types.rs:38

pub struct NdcColumnForComparison {
    pub column: DataConnectorColumnName,
    pub equal_operator: DataConnectorOperatorName,
}

/// Track the root fields of the GraphQL schema while resolving the metadata.
/// This is used to ensure that the schema has unique root fields for Query, Mutation and Subscription.
// NOTE: The `ast::Name` is cheap to clone, so storing them directly without references
pub struct TrackGraphQLRootFields {
    pub query: BTreeSet<ast::Name>,
    pub mutation: BTreeSet<ast::Name>,
    pub subscription: BTreeSet<ast::Name>,
}

#[derive(Debug, thiserror::Error)]
pub enum DuplicateRootFieldError {
    #[error("Cannot add query root field {0} as it already in use")]
    Query(ast::Name),
    #[error("Cannot add mutation root field {0} as it already in use")]
    Mutation(ast::Name),
    #[error("Cannot add subscription root field {0} as it already in use")]
    Subscription(ast::Name),
}

impl TrackGraphQLRootFields {
    pub fn new() -> Self {
        Self {
            query: BTreeSet::new(),
            mutation: BTreeSet::new(),
            subscription: BTreeSet::new(),
        }
    }
    pub fn track_query_root_field(
        &mut self,
        name: &ast::Name,
    ) -> Result<(), DuplicateRootFieldError> {
        if !self.query.insert(name.clone()) {

View on GitHub (pinned to 724551b9ae)

Solutions

  1. Rename one mutation's GraphQL field name to be unique
  2. Remove the stale duplicate command from metadata
  3. Namespace mutation names per connector/domain (e.g. orders_insert vs users_insert)

Example fix

# before
- kind: Command
  name: insert_user
  # in two different modules

# after
- kind: Command
  name: insert_user_v2   # unique name in the second module
Defensive patterns

Strategy: validation

Validate before calling

if !mutation_fields.insert(name.clone()) {
    return Err(format!("duplicate mutation root field: {name}"));
}

Try / catch

match err {
    DuplicateRootFieldError::Mutation(name) => eprintln!("two mutations expose '{name}'; rename one"),
    _ => {}
}

Prevention

When it happens

Trigger: Registering two mutations (commands) with the same GraphQL name on the Mutation root, e.g. two create_/update_ commands both named insert_user in different modules.

Common situations: Copy-pasted command definitions, multiple data connectors each defining a mutation with the same name, refactors that moved a command without renaming it.

Related errors


AI-assisted analysis of hasura/graphql-engine@724551b9ae (2026-08-28). Data as JSON: /api/errors/b9792bb33a8db661. Report an issue: GitHub.