You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Retrieving the status of an Open Banking (GP-ECOM) transaction via ReportBuilder.Execute() throws an unhandled System.InvalidCastException from inside GlobalPayments.Api.dll.
The crash happens while mapping the report response when the created_on field arrives as a JSON array (parsed to List<string>) rather than a single scalar value. This exception is not caught and propagates out of the SDK, taking down the caller's execution thread.
Affected Versions
Confirmed present and unchanged in versions: 8.0.19, 9.0.0, 10.0.0, and 11.0.4 (current latest on NuGet). Upgrading does not resolve the issue as the underlying parsing logic remains identical across these releases.
System.InvalidCastException: Unable to cast object of type 'System.Collections.Generic.List`1[System.String]' to type 'System.DateTime'.
at GlobalPayments.Api.Utils.JsonDoc.GetValue[T](String name, Func`2 converter)
at GlobalPayments.Api.Mapping.OpenBankingMapping.MapTransactionSummary(JsonDoc response)
at GlobalPayments.Api.Mapping.OpenBankingMapping.MapReportResponse`1(String rawResponse, ReportType reportType)
at GlobalPayments.Api.Gateways.OpenBankingProvider.ProcessReport[T](ReportBuilder`1 builder)
at GlobalPayments.Api.Builders.ReportBuilder`1.Execute(String configName)
Root Cause
The crash results from two interacting issues within src/GlobalPayments.Api/Utils/JsonUtils.cs:
1. Array Coercion to List<string>
In ParseObject, any field whose value is a JSON array of primitives/non-objects is eagerly stored via ParseTypeArray<string>:
else{varobjs=ParseTypeArray<string>(child.ValueasJArray,encoder);values.Add(child.Name,objs);// Stored in the internal dictionary as List<string>}
When a payload contains "created_on": ["2026-06-11T11:29:35Z"], a List<string> is stored under that dictionary key.
2. Double-Faulting in GetValue<T> Fallback
Convert.ChangeType throws an InvalidCastException because List<string> does not implement IConvertible. The catch block attempts a direct cast to T (DateTime), which immediately throws a second InvalidCastException. Because this second exception occurs inside the catch block, it escapes the method completely.
publicTGetValue<T>(stringname,Func<object,T>converter=null){if(_dict.ContainsKey(name)&&_dict[name]!=null){try{varvalue=_dict[name];// ...elsereturn(T)Convert.ChangeType(value,typeof(T));// Throws: List<string> is not IConvertible}catch(InvalidCastException){return(T)_dict[name];// Throws AGAIN: Direct cast from List<string> to DateTime fails}}returndefault(T);}
This path is triggered directly during transaction mapping in src/GlobalPayments.Api/Mapping/OpenBankingMapping.cs:
The SDK will fail immediately with the InvalidCastException stack trace instead of returning a populated TransactionSummary object.
Expected Behavior
The SDK must handle type anomalies gracefully without throwing unhandled infrastructure exceptions. It should either:
Extract and parse the first element when an array is unexpectedly provided for a scalar property.
Degrade gracefully by returning default(T) if the internal data structure cannot be cast to the target type.
Suggested Fix
Tip
Resolving Fix 1 offers the highest value across the SDK, preventing unhandled dictionary casting failures for all types. Implementing Fix 2 guarantees that unexpected Open Banking array variants map to valid dates instead of zeroing out.
Fix 1: Harden GetValue<T> and GetNullableValue<T>
Safeguard the fallback path using a pattern matching or safe type check compatible with .NET Standard 1.3:
Fix 2: Implement Array Tolerance in Open Banking Mappings
Update MapTransactionSummary to safely intercept and unpack string collections:
summary.TransactionDate=response.GetValue<DateTime>("created_on", o =>Convert.ToDateTime(oisSystem.Collections.IListlist?list[0]:o));
Note
This issue addresses SDK resilience. A separate engineering review should evaluate why the Open Banking gateway serialization pipeline wrapped the created_on timestamp in an array context in the first place.
Summary
Retrieving the status of an Open Banking (GP-ECOM) transaction via
ReportBuilder.Execute()throws an unhandledSystem.InvalidCastExceptionfrom insideGlobalPayments.Api.dll.The crash happens while mapping the report response when the
created_onfield arrives as a JSON array (parsed toList<string>) rather than a single scalar value. This exception is not caught and propagates out of the SDK, taking down the caller's execution thread.Affected Versions
Confirmed present and unchanged in versions: 8.0.19, 9.0.0, 10.0.0, and 11.0.4 (current latest on NuGet). Upgrading does not resolve the issue as the underlying parsing logic remains identical across these releases.
Execution Flow
Stack Trace
Root Cause
The crash results from two interacting issues within
src/GlobalPayments.Api/Utils/JsonUtils.cs:1. Array Coercion to
List<string>In
ParseObject, any field whose value is a JSON array of primitives/non-objects is eagerly stored viaParseTypeArray<string>:When a payload contains
"created_on": ["2026-06-11T11:29:35Z"], aList<string>is stored under that dictionary key.2. Double-Faulting in
GetValue<T>FallbackConvert.ChangeTypethrows anInvalidCastExceptionbecauseList<string>does not implementIConvertible. Thecatchblock attempts a direct cast toT(DateTime), which immediately throws a secondInvalidCastException. Because this second exception occurs inside thecatchblock, it escapes the method completely.This path is triggered directly during transaction mapping in
src/GlobalPayments.Api/Mapping/OpenBankingMapping.cs:Steps to Reproduce
ReportBuilderquery to fetch an Open Banking / bank-payment transaction status.created_onproperty wrapped inside a JSON array:{ "payments": [ { "ob_trans_id": "example-id", "status": "CAPTURED", "amount": "10.00", "currency": "GBP", "created_on": ["2026-06-11T11:29:35Z"] } ] }InvalidCastExceptionstack trace instead of returning a populatedTransactionSummaryobject.Expected Behavior
The SDK must handle type anomalies gracefully without throwing unhandled infrastructure exceptions. It should either:
default(T)if the internal data structure cannot be cast to the target type.Suggested Fix
Tip
Resolving Fix 1 offers the highest value across the SDK, preventing unhandled dictionary casting failures for all types. Implementing Fix 2 guarantees that unexpected Open Banking array variants map to valid dates instead of zeroing out.
Fix 1: Harden
GetValue<T>andGetNullableValue<T>Safeguard the fallback path using a pattern matching or safe type check compatible with
.NET Standard 1.3:Fix 2: Implement Array Tolerance in Open Banking Mappings
Update
MapTransactionSummaryto safely intercept and unpack string collections:Note
This issue addresses SDK resilience. A separate engineering review should evaluate why the Open Banking gateway serialization pipeline wrapped the
created_ontimestamp in an array context in the first place.