hasura/graphql-engine · error · RelayError

'globalIdFields' for type {object_type:} found, but no model

Error message

'globalIdFields' for type {object_type:} found, but no model found with 'globalIdSource: true' for type {object_type:}

What it means

Relay stage error: an object type declares globalIdFields, but no model implementing that object type is flagged globalIdSource: true. The Relay global ID machinery needs exactly one backing model to build IDs from those fields, so resolution fails when the flag is missing.

Source

Thrown at v3/crates/metadata-resolve/src/stages/relay/mod.rs:26

/// Ideally, we could move more Relay-based resolving into this discreet step, haven't
/// investigated this too deeply yet.
pub fn resolve(
    global_id_enabled_types: BTreeMap<Qualified<CustomTypeName>, Vec<Qualified<ModelName>>>,
) -> Result<(), RelayError> {
    // To check if global_id_fields are defined in object type but no model has global_id_source set to true:
    //   - Throw an error if no model with globalIdSource:true is found for the object type.
    for (object_type, model_name_list) in global_id_enabled_types {
        if model_name_list.is_empty() {
            return Err(RelayError::GlobalIdSourceNotDefined { object_type });
        }
    }

    Ok(())
}

#[derive(Debug, thiserror::Error)]
pub enum RelayError {
    #[error(
        "'globalIdFields' for type {object_type:} found, but no model found with 'globalIdSource: true' for type {object_type:}"
    )]
    GlobalIdSourceNotDefined {
        object_type: Qualified<CustomTypeName>,
    },
    #[error(
        "Model {model_name:} is marked as a global ID source but there are no global id fields present in the related object type {type_name:}"
    )]
    NoGlobalFieldsPresentInGlobalIdSource {
        type_name: Qualified<CustomTypeName>,
        model_name: ModelName,
    },
    #[error(
        "Found multiple models  {model_1:}, {model_2:} that implement the same object type {object_type:} to be global ID sources."
    )]
    DuplicateModelGlobalIdSource {
        model_1: Qualified<ModelName>,
        model_2: Qualified<ModelName>,

View on GitHub (pinned to 724551b9ae)

Solutions

  1. Find the model that implements the object type named in the error and set globalIdSource: true on it
  2. Verify the model's object type mapping actually points at the annotated type
  3. If globalIdFields were added by mistake, remove them from the object type

Example fix

# before
kind: Model
name: Users
objectType: User
# type User has globalIdFields: [id]
# after
kind: Model
name: Users
objectType: User
globalIdSource: true
Defensive patterns

Strategy: validation

Validate before calling

fn check_global_id_pairs(models: &[Model], types: &[ObjectType]) -> Result<(), String> {
    for t in types {
        if t.global_id_fields.is_empty() { continue; }
        let ok = models.iter().any(|m| m.object_type == t.name && m.global_id_source);
        if !ok { return Err(format!("type {} has globalIdFields but no globalIdSource model", t.name)); }
    }
    Ok(())
}

Try / catch

match on RelayError::GlobalIdSourceNotDefined and print the object type plus the models implementing it to guide the fix

Prevention

When it happens

Trigger: Adding globalIdFields to an object type in OpenDD metadata without setting globalIdSource: true on any model that implements that type; or setting the flag on a model targeting a different object type.

Common situations: Enabling Relay-style pagination incrementally — the type annotation lands but the model flag is forgotten; refactoring model-to-type mappings so the flagged model no longer implements the annotated type.

Related errors


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