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
- Validate the metadata JSON against the `GlobalpayMetadata` schema before sending it (correct field names and types, e.g. `account_name` as an optional string)
- Remove the metadata field if Globalpay-specific metadata is not needed (metadata is optional)
- Migrate/repair any stored connector metadata rows that fail deserialization
- 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
- Validate metadata against GlobalpayMetadata before persisting or sending
- Treat metadata as optional; omit it rather than sending an empty or wrong-typed object
- Add serde round-trip tests for GlobalpayMetadata to catch schema drift
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
- Globalpay requires BodyKey auth type
- Datatrans requires BodyKey auth type
- Etisalat requires SignatureKey auth type
- Merchante requires BodyKey auth type
- a captured response must reconstruct
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)