juspay/hyperswitch · error · ApiErrorResponse
Invalid Calida metadata format
Error message
Invalid Calida metadata format
What it means
Thrown while building the X_CONNECTOR_CONFIG header for the Calida connector (ConnectorSpecificConfig::foreign_try_from via build_connector_config_header, connector_config.rs:1876). Calida requires HeaderKey auth, and when the merchant account carries a metadata JSON value, serde_json::from_value::<CalidaMetadata> must deserialize it into CalidaMetadata { shop_name: Secret<String> }. Any serde failure is collapsed into this single message, so the real cause (missing shop_name, non-string shop_name, or non-object metadata) is hidden.
Source
Thrown at crates/router/src/core/unified_connector_service/connector_config.rs:932
ConnectorAuthType::MultiAuthKey {
api_key,
key1,
api_secret,
key2,
} => Ok(Self::Fiservcommercehub {
api_key: api_key.clone(),
secret: api_secret.clone(),
merchant_id: key1.clone(),
terminal_id: key2.clone(),
}),
_ => Err(err("Fiservcommercehub requires MultiAuthKey auth type")),
},
Connector::Calida => match auth {
ConnectorAuthType::HeaderKey { api_key } => {
let calida_meta = metadata
.map(|m| {
serde_json::from_value::<CalidaMetadata>(m.clone())
.map_err(|_| err("Invalid Calida metadata format"))
})
.transpose()?;
Ok(Self::Calida {
api_key: api_key.clone(),
shop_name: calida_meta.as_ref().map(|m| m.shop_name.clone()),
})
}
_ => Err(err("Calida requires HeaderKey auth type")),
},
Connector::Celero => match auth {
ConnectorAuthType::HeaderKey { api_key } => Ok(Self::Celero {
api_key: api_key.clone(),
}),
_ => Err(err("Celero requires HeaderKey auth type")),
},
Connector::Helcim => match auth {
ConnectorAuthType::HeaderKey { api_key } => Ok(Self::Helcim {View on GitHub (pinned to 3093f22cc4)
Solutions
- Fix the merchant connector account metadata to a flat object with a string shop_name, e.g. {"shop_name": "my-shop"}, via the connector account update API.
- If the metadata was nested ({"calida": {...}}) remove the wrapper; CalidaMetadata is deserialized directly from the top-level value.
- If you do not need a shop name, set metadata to null/None entirely — metadata is Option and Calida builds fine without it (shop_name becomes None).
- As a library maintainer, replace .map_err(|_| err(...)) with .attach_printable/format! of the underlying serde error so the actual field problem is reported.
Example fix
// before — merchant connector account for Calida (metadata fails to deserialize)
"metadata": { "shop": "my-calida-shop" } // wrong key name
// after
"metadata": { "shop_name": "my-calida-shop" } Defensive patterns
Strategy: validation
Validate before calling
// Run before building the header / before relying on a Calida account
fn calida_metadata_ok(metadata: Option<&serde_json::Value>) -> bool {
match metadata {
None => true, // metadata is optional for Calida
Some(v) => v
.get("shop_name")
.map(|s| s.is_string() && !s.as_str().unwrap_or_default().is_empty())
.unwrap_or(false),
}
} Type guard
fn is_valid_calida_metadata(metadata: &serde_json::Value) -> bool {
#[derive(serde::Deserialize)]
struct CalidaMeta { shop_name: masking::Secret<String> }
serde_json::from_value::<CalidaMeta>(metadata.clone()).is_ok()
} Try / catch
// Rust: treat as a config error surfaced to the operator, not a runtime retry
let header = build_connector_config_header(connector, &auth, metadata.map(|m| m.borrow())).map_err(|e| {
if e.current_context().message.contains("Calida metadata") {
// actionable: point at the connector account's metadata field
ReportConfigError { field: "metadata.shop_name", fix: "supply a string shop_name or remove metadata" }
} else { e }
})?; Prevention
- When creating Calida accounts, always send metadata as {"shop_name": "<string>"} or omit it entirely.
- Add an integration test that round-trips every connector's metadata through its expected struct at account-create time.
- Never wrap connector-specific metadata in a per-connector envelope key; all CalidaMetadata fields are read from the top level.
- Log the underlying serde error (not just this message) in your wrapper so future misconfigurations are diagnosable.
When it happens
Trigger: A Calida merchant connector account was created with auth_type HeaderKey and a non-null metadata field, then any UCS (unified connector service) request path calls build_connector_config_header(Connector::Calida, auth, Some(metadata)). It fails when metadata is not a JSON object, lacks a shop_name key, or shop_name is not a string (e.g. {"shop_name": 12345} or {"shop": "x"}). Note the struct has no deny_unknown_fields, so extra keys are fine; only shop_name's presence and string type matter.
Common situations: Typo in the metadata field name (shop vs shop_name) when creating the merchant connector via the admin API; metadata reused from another connector (e.g. a nested {"calida": {"shop_name": ...}} wrapper); a dashboard/form that submits numbers for shop names; or an account created before shop_name metadata was required, later routed through the UCS path.
Related errors
- Ilixium requires SignatureKey auth type
- Iatapay requires SignatureKey auth type
- Moneris requires SignatureKey auth type
- Invalid Worldpayxml metadata format
- Worldpayxml requires SignatureKey auth type
AI-assisted analysis of juspay/hyperswitch@3093f22cc4 (2026-08-23).
Data as JSON: /api/errors/53a747034837bf84.
Report an issue: GitHub.