Skip to content

[Bug]: PaymentMethodsResponse deserialization fails in Checkout after the System.Text.Json migration introduced in v34.0.0 #1474

@jorismathijssen

Description

@jorismathijssen

Description

After upgrading to Adyen .NET API Library v34.x, we are seeing a deserialization regression in a Checkout model after the library-wide System.Text.Json migration introduced in v34.0.0. Our concrete reproducible case is PaymentMethodsAsync: Adyen returns HTTP 200 OK, but the Adyen .NET API Library fails while deserializing the successful response into Adyen.Checkout.Models.PaymentMethodsResponse. The failure appears to be caused by the PaymentMethodsResponse model shape in 34.0.2. The type has a [JsonConstructor] whose parameters use Option<List<...>>, while the JSON-facing properties are List<...>. System.Text.Json rejects this constructor binding. This may be related to the broader STJ migration already visible elsewhere in the library, but this report is specifically about a Checkout model deserialization failure in 34.0.2.

Steps to reproduce

  1. Install Adyen .NET API Library 34.0.2.
  2. Call Checkout paymentMethods through PaymentsService.PaymentMethodsAsync(...).
  3. Receive a valid HTTP 200 OK response from Adyen.
  4. Call TryDeserializeOkResponse(out PaymentMethodsResponse result).
  5. Observe deserialization failure.

Minimal reproduction without making a real HTTP request:

  1. Install Adyen .NET API Library 34.0.2.
  2. Deserialize the following JSON into Adyen.Checkout.Models.PaymentMethodsResponse using System.Text.Json.
  3. Observe InvalidOperationException.

Actual behavior

Deserialization fails with:

System.InvalidOperationException: Each parameter in the deserialization constructor on type 'Adyen.Checkout.Models.PaymentMethodsResponse' must bind to an object property or field on deserialization. Each parameter name must match with a property or field on the object. Fields are only considered when 'JsonSerializerOptions.IncludeFields' is enabled. The match can be case-insensitive.

In the Adyen SDK logging this appears as:

An error occurred while deserializing the "OK" response.

Expected behavior

If Adyen returns HTTP 200 OK for /paymentMethods, the library should deserialize the response into PaymentMethodsResponse successfully.

More generally, the System.Text.Json migration introduced in v34.0.0 should not leave Checkout response models in a state where they cannot be deserialized by the library itself.

Code snippet or screenshots (if applicable)

Runtime path:

var apiResponse = await checkout.PaymentMethodsAsync(paymentMethodsRequest, null, default);

if (!apiResponse.TryDeserializeOkResponse(out PaymentMethodsResponse response))
{
    throw new Exception("Failed to deserialize Adyen payment methods response.");
}

Minimal reproduction:

using System.Text.Json;
using Adyen.Checkout.Models;

var json = "{\"paymentMethods\":[],\"storedPaymentMethods\":[]}";

var result = JsonSerializer.Deserialize<PaymentMethodsResponse>(json);

Relevant model shape observed from 34.0.2:

[JsonConstructor]
PaymentMethodsResponse(
    Option<List<PaymentMethod>> paymentMethods,
    Option<List<StoredPaymentMethod>> storedPaymentMethods)

public List<PaymentMethod> PaymentMethods { get; set; }            // json name: paymentMethods
public List<StoredPaymentMethod> StoredPaymentMethods { get; set; } // json name: storedPaymentMethods

This seems incompatible with System.Text.Json constructor binding.

Adyen .NET API Library version

34.0.2

.NET version

.NET 8

Operating System

Windows

Additional context

  • The HTTP request itself succeeds and Adyen returns 200 OK.
  • This appears to be a model/deserialization issue, not a request formatting issue.
  • We reproduced the problem locally without calling the real API by deserializing a minimal JSON payload directly into PaymentMethodsResponse.
  • PropertyNameCaseInsensitive = true does not fix it.
  • IncludeFields = true does not fix it.
  • Forcing System.Text.Json to use the parameterless constructor for this type does work, which suggests the problem is specifically the [JsonConstructor] path on PaymentMethodsResponse.
  • v34.0.0 release notes explicitly mention:
    Support native System.Text.Json for serialization and deserialization.
  • We do not see anything in the v34.0.0 release notes that suggests consumers should apply a special Checkout-specific migration step for PaymentMethodsResponse.
  • 34.0.2 release notes do not mention a fix related to Checkout model deserialization; they only mention:
    Fix Classic Recurring live URL (#1444)

.Net Fiddle: https://dotnetfiddle.net/eaXF1g

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions