{"record":{"id":"53a747034837bf84","repo":"juspay/hyperswitch","slug":"invalid-calida-metadata-format","errorCode":null,"errorMessage":"Invalid Calida metadata format","messagePattern":"Invalid Calida metadata format","errorType":"exception","errorClass":"ApiErrorResponse","httpStatus":500,"severity":"error","filePath":"crates/router/src/core/unified_connector_service/connector_config.rs","lineNumber":932,"sourceCode":"                ConnectorAuthType::MultiAuthKey {\n                    api_key,\n                    key1,\n                    api_secret,\n                    key2,\n                } => Ok(Self::Fiservcommercehub {\n                    api_key: api_key.clone(),\n                    secret: api_secret.clone(),\n                    merchant_id: key1.clone(),\n                    terminal_id: key2.clone(),\n                }),\n                _ => Err(err(\"Fiservcommercehub requires MultiAuthKey auth type\")),\n            },\n            Connector::Calida => match auth {\n                ConnectorAuthType::HeaderKey { api_key } => {\n                    let calida_meta = metadata\n                        .map(|m| {\n                            serde_json::from_value::<CalidaMetadata>(m.clone())\n                                .map_err(|_| err(\"Invalid Calida metadata format\"))\n                        })\n                        .transpose()?;\n\n                    Ok(Self::Calida {\n                        api_key: api_key.clone(),\n                        shop_name: calida_meta.as_ref().map(|m| m.shop_name.clone()),\n                    })\n                }\n                _ => Err(err(\"Calida requires HeaderKey auth type\")),\n            },\n            Connector::Celero => match auth {\n                ConnectorAuthType::HeaderKey { api_key } => Ok(Self::Celero {\n                    api_key: api_key.clone(),\n                }),\n                _ => Err(err(\"Celero requires HeaderKey auth type\")),\n            },\n            Connector::Helcim => match auth {\n                ConnectorAuthType::HeaderKey { api_key } => Ok(Self::Helcim {","sourceCodeStart":914,"sourceCodeEnd":950,"githubUrl":"https://github.com/juspay/hyperswitch/blob/3093f22cc46b46415cca152ea0b234277b251ecd/crates/router/src/core/unified_connector_service/connector_config.rs#L914-L950","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before — merchant connector account for Calida (metadata fails to deserialize)\n\"metadata\": { \"shop\": \"my-calida-shop\" }   // wrong key name\n\n// after\n\"metadata\": { \"shop_name\": \"my-calida-shop\" }","handlingStrategy":"validation","validationCode":"// Run before building the header / before relying on a Calida account\nfn calida_metadata_ok(metadata: Option<&serde_json::Value>) -> bool {\n    match metadata {\n        None => true, // metadata is optional for Calida\n        Some(v) => v\n            .get(\"shop_name\")\n            .map(|s| s.is_string() && !s.as_str().unwrap_or_default().is_empty())\n            .unwrap_or(false),\n    }\n}","typeGuard":"fn is_valid_calida_metadata(metadata: &serde_json::Value) -> bool {\n    #[derive(serde::Deserialize)]\n    struct CalidaMeta { shop_name: masking::Secret<String> }\n    serde_json::from_value::<CalidaMeta>(metadata.clone()).is_ok()\n}","tryCatchPattern":"// Rust: treat as a config error surfaced to the operator, not a runtime retry\nlet header = build_connector_config_header(connector, &auth, metadata.map(|m| m.borrow())).map_err(|e| {\n    if e.current_context().message.contains(\"Calida metadata\") {\n        // actionable: point at the connector account's metadata field\n        ReportConfigError { field: \"metadata.shop_name\", fix: \"supply a string shop_name or remove metadata\" }\n    } else { e }\n})?;","preventionTips":["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."],"tags":["calida","serde","json-metadata","deserialization","connector-config","hyperswitch"],"backgroundTag":"json-deserialization-failed","analyzedSha":"3093f22cc46b46415cca152ea0b234277b251ecd","analyzedAt":"2026-08-23T00:36:32.882Z","contentChangedAt":"2026-08-23T00:36:32.882Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}