juspay/hyperswitch · error

Invalid Globalpay metadata format

Error message

Invalid Globalpay metadata format

What it means

When building the Globalpay connector config, optional connector metadata is deserialized into `GlobalpayMetadata` via serde_json. If metadata JSON is present but does not match the `GlobalpayMetadata` schema, the deserialization is mapped to this error. It indicates malformed Globalpay-specific configuration data accompanying the credential.

Solutions

  1. Validate the metadata JSON against the `GlobalpayMetadata` schema before sending it (correct field names and types, e.g. `account_name` as an optional string)
  2. Remove the metadata field if Globalpay-specific metadata is not needed (metadata is optional)
  3. Migrate/repair any stored connector metadata rows that fail deserialization
  4. Check for a recent `GlobalpayMetadata` struct change and align the supplied payload

Example fix

// before
metadata: json!({"account_name": 42})
// after
metadata: json!({"account_name": "my-account"})
Defensive patterns

Strategy: validation

Validate before calling

if let Some(m) = &metadata {
    let meta: GlobalpayMetadata = serde_json::from_value(m.clone())
        .map_err(|e| report!(ConfigError::InvalidMetadata(e.to_string())))?;
    assert!(meta.account_name.as_deref().map_or(true, |s| !s.is_empty()));
}

Type guard

fn is_valid_globalpay_metadata(v: &serde_json::Value) -> bool {
    v.as_object().map_or(false, |o| {
        o.get("account_name").map_or(true, |a| a.is_string())
    })
}

Try / catch

match serde_json::from_value::<GlobalpayMetadata>(metadata.clone()) {
    Ok(m) => proceed(m),
    Err(e) => log::warn!("Globalpay metadata rejected: {e}"),
}

Prevention

When it happens

Trigger: Calling connector config creation for `Connector::Globalpay` with a `metadata` JSON value whose fields do not conform to `GlobalpayMetadata` (wrong types, unknown required fields, non-object value), e.g. `metadata: {"account_name": 123}` instead of a string.

Common situations: Hand-edited merchant metadata in the DB or dashboard; API callers passing free-form metadata assuming it is passthrough; schema drift after a `GlobalpayMetadata` field type change with stale stored metadata.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of juspay/hyperswitch@afd9284352 (2026-09-18). Data as JSON: /api/errors/e40f75be8034da89. Report an issue: GitHub.

Appendix: source

Thrown at crates/router/src/core/unified_connector_service/connector_config.rs:1064

                ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self::Cryptopay {
                    api_key: api_key.clone(),
                    api_secret: key1.clone(),
                }),
                _ => Err(err("Cryptopay requires BodyKey auth type")),
            },
            Connector::Datatrans => match auth {
                ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self::Datatrans {
                    merchant_id: key1.clone(),
                    password: api_key.clone(),
                }),
                _ => Err(err("Datatrans requires BodyKey auth type")),
            },
            Connector::Globalpay => match auth {
                ConnectorAuthType::BodyKey { api_key, key1 } => {
                    let globalpay_meta = metadata
                        .map(|m| {
                            serde_json::from_value::<GlobalpayMetadata>(m.clone())
                                .map_err(|_| err("Invalid Globalpay metadata format"))
                        })
                        .transpose()?;

                    Ok(Self::Globalpay {
                        app_id: key1.clone(),
                        app_key: api_key.clone(),
                        account_name: globalpay_meta.and_then(|m| m.account_name),
                    })
                }
                _ => Err(err("Globalpay requires BodyKey auth type")),
            },
            Connector::Hipay => match auth {
                ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self::Hipay {
                    api_key: api_key.clone(),
                    api_secret: key1.clone(),
                }),
                _ => Err(err("Hipay requires BodyKey auth type")),
            },

View on GitHub (pinned to afd9284352)