hasura/graphql-engine · error · Error

multiple definitions of graphql type: {0:}

Error message

multiple definitions of graphql type: {0:}

What it means

Schema-building error: while merging type definitions from the parsed SDL, two definitions resolved to the same type name with conflicting definitions, so a single schema cannot be built. The conflicting ast::TypeName is reported.

Source

Thrown at v3/crates/graphql/lang-graphql/src/schema/build.rs:20

use thiserror::Error;

use crate::ast::common as ast;
use crate::ast::schema as sdl;
use crate::ast::schema::ConstDirective;
use crate::ast::spanning::Positioned;
use crate::ast::spanning::Spanning;
use crate::parser;

#[derive(Error, Debug, Clone)]
pub enum Error {
    #[error("internal error when parsing introspection schema : {0:}")]
    InternalParseError(Positioned<parser::Error>),

    #[error("internal error when building schema: {0:}")]
    Internal(String),

    #[error("multiple definitions of graphql type: {0:}")]
    ConflictingGraphQlType(ast::TypeName),
}

pub type Result<T> = core::result::Result<T, Error>;

pub fn build_schema<S>(s: &S) -> std::result::Result<Schema<S>, S::SchemaError>
where
    S: SchemaContext,
{
    let introspection_schema = include_str!("introspection.graphql");
    let introspection_document = parser::Parser::new(introspection_schema)
        .parse_schema_document()
        .map_err(Error::InternalParseError)?;
    let mut types = BTreeMap::new();
    let mut introspection_root_fields = BTreeMap::new();
    let mut builder = Builder {
        registered_types: HashSet::new(),
        registered_namespaces: HashSet::new(),

View on GitHub (pinned to 724551b9ae)

Solutions

  1. Search the SDL for the reported type name and deduplicate/merge the definitions
  2. If merging files, exclude one of the conflicting definitions at load time
  3. If extending a type, use `extend type Foo` instead of redefining it
  4. Check generated SDL output for duplicated blocks after codegen changes

Example fix

# before
type User { id: ID }
type User { name: String }
# after
type User { id: ID, name: String }
# or: type User { id: ID }  extend type User { name: String }
Defensive patterns

Strategy: validation

Validate before calling

fn find_duplicate_types(docs: &[Document]) -> Vec<TypeName> {
    let mut seen = HashSet::new();
    docs.iter().flat_map(|d| d.definitions()).filter_map(|def| def.as_type_def())
        .filter(|t| !seen.insert(t.name.clone())).map(|t| t.name.clone()).collect()
}
assert!(find_duplicate_types(&docs).is_empty());

Try / catch

match build_schema(&defs) { Err(Error::ConflictingGraphQlType(name)) => dedupe_or_report(name), _ => {} } — build_schema returns S::SchemaError, so map this variant at the call site.

Prevention

When it happens

Trigger: Calling build_schema on a schema definition that defines the same type (e.g. type Foo {...} twice, or type Foo and interface/enum Foo) in separate definitions; also when stitching a base schema with introspection schema types that collide.

Common situations: Schema stitching or merging multiple .graphql files that both define a type; copy-pasted type blocks; re-importing a module that already declares a type; version bumps adding duplicate definitions to generated SDL.

Related errors


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