Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Failure to parse response from /v1/forwarding/requests #3028

Open
dgregory-resnexus opened this issue Nov 8, 2024 · 9 comments
Open

Failure to parse response from /v1/forwarding/requests #3028

dgregory-resnexus opened this issue Nov 8, 2024 · 9 comments
Assignees
Labels

Comments

@dgregory-resnexus
Copy link

dgregory-resnexus commented Nov 8, 2024

Describe the bug

When making a request to the /v1/forwarding/requests endpoint using v45.11 or v47.0 of the SDK, the response fails to be parsed.

It appears to me that it is the value of "created" (1731082862469) that is failing to parse. In a different successful request to a different endpoint, the value of "created" was 1731082744. The one that is failing appears to be in milliseconds and the one that is working appears to be in seconds.

To Reproduce

Make any request to the endpoint using the SDK.
I used the suggested sample from the API docs

Expected behavior

Parse the response correctly

Code snippets

{ "id": "fwdreqm_ymtq5DT1Y!LQxwPJEesM6wfg0Rf68V9QxssGDwpSzBw*EhcKFWFjY3RfMVB2blRrUFE2d2VhS3JKTw", "object": "forwarding.request", "created": 1731082862469, "livemode": false, "payment_method": "pm_1QIutzPQ6weaKrJOWhTfGN3x", "replacements": [ "card_number", "card_expiry", "cardholder_name" ], "request_context": { "destination_duration": 89, "destination_ip_address": "35.190.113.80" }, "request_details": { "body": "{\"card\":{\"exp_month\":\"02\", \"exp_year\":\"2025\", \"name\":\"REDACTED3\", \"number\":\"555555******4444\"}, \"metadata\":{\"REDACTED1\":\"1954\", \"REDACTED2\":\"4\"}}", "headers": [ { "name": "Authorization", "value": "Bearer *******************************************************************************************" }, { "name": "Content-Type", "value": "application/json" } ], "http_method": "POST" }, "response_details": { "body": "{\"id\":\"token_1\"}", "headers": [ { "name": "Content-Length", "value": "16" }, { "name": "Etag", "value": "W/\"10-eOqXY39ivjugjwCuZPjsCZw1UEE\"" }, { "name": "Via", "value": "1.1 google" }, { "name": "X-Powered-By", "value": "Express" }, { "name": "X-Robots-Tag", "value": "noindex, nofollow" }, { "name": "Content-Type", "value": "application/json; charset=utf-8" }, { "name": "Server", "value": "envoy" }, { "name": "Alt-Svc", "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" }, { "name": "Date", "value": "Fri, 08 Nov 2024 16:21:02 GMT" }, { "name": "X-Cloud-Trace-Context", "value": "aa86744918565aa04aba1d2909d56221;o=1" } ], "status": 200 }, "url": "https://forwarding-api-demo.stripedemos.com/tokens"}

OS

Windows 11

.NET version

.NET 4.7.2

Library version

stripe-dotnet-v45.11

API version

2024-09-05

Additional context

System.ArgumentOutOfRangeException
Value to add was out of range

Partial Stack Trace
at System.DateTime.Add(Double value, Int32 scale) in System\DateTime.cs:line 860
at Stripe.Infrastructure.UnixDateTimeConverter.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer) in //src/Stripe.net/Infrastructure/JsonConverters/UnixDateTimeConverter.cs:line 87
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Populate(JsonReader reader, Object target)
at Stripe.Infrastructure.StripeEntityConverter.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer) in /
/src/Stripe.net/Infrastructure/JsonConverters/StripeEntityConverter.cs:line 74

@dgregory-resnexus
Copy link
Author

FYI the code snippet I provided is the redacted response I retrieved from my Stripe dashboard

@dgregory-resnexus
Copy link
Author

dgregory-resnexus commented Nov 8, 2024

https://github.com/stripe/stripe-dotnet/blob/master/src/Stripe.net/Infrastructure/JsonConverters/UnixDateTimeConverter.cs

Line 87. Most responses (the working ones) are actually being returned in seconds, but the forwarding API is responding in milliseconds, which is why adding seconds to UnixEpoch is failing (it's adding milliseconds instead of actual seconds and causing an overflow).

@dgregory-resnexus
Copy link
Author

dgregory-resnexus commented Nov 8, 2024

Possible solution 1:

long maxSeconds = TimeSpan.FromTicks(DateTime.MaxValue.Ticks - UnixEpoch.Ticks).TotalSeconds;

if (seconds > maxSeconds)
{
    return UnixEpoch.AddMilliseconds(seconds);
}
else if (seconds >= 0)
{
    return UnixEpoch.AddSeconds(seconds);
}
else
{
    throw new JsonSerializationException(string.Format("Cannot convert value that is before Unix epoch of 00:00:00 UTC on 1 January 1970 to {0}.", objectType));
}

Possible solution 2 (avoids SDK fix)
Fix the response from the API to return seconds instead of milliseconds

@jar-stripe
Copy link
Contributor

Hi @dgregory-resnexus , thanks for the report and the investigation! We'll take a look and update here when we have more info.

@dgregory-resnexus
Copy link
Author

Absolutely!

The value for maxSeconds could probably be initialized as static readonly like UnixEpoch, so it wouldn't have to be recalculated every time.

@jar-stripe jar-stripe self-assigned this Nov 12, 2024
@jar-stripe
Copy link
Contributor

Hi @dgregory-resnexus , thanks for your patience here! Just wanted to let you know that we're working on a fix to the API so this will return seconds as expected. I will update you when it is ready; in the mean time, if this is blocking you, you may be able to use stripe-dotnet Custom Request feature (introduced in v46, https://github.com/stripe/stripe-dotnet/?tab=readme-ov-file#custom-requests) as a workaround. RawRequest does not deserialize the response, which means it will not encounter this error but you will need to parse and process the response yourself. Hope that helps; will be back in touch when I know more!

@dgregory-resnexus
Copy link
Author

I'll wait for the API fix, I'm not in a rush.

I already updated to v47 of the SDK, so the workaround will be helpful if my timeline becomes more urgent.

@empowerjamesgarrett
Copy link

Could we clarify what the fix that's in progress is?

If we were to make the change @dgregory-resnexus is suggesting, the real world impact would be near zero, but it would "technically" be a breaking change. We could limit it to just the impacted API versions to make it even safer.

@jar-stripe
Copy link
Contributor

jar-stripe commented Nov 20, 2024

Hi @empowerjamesgarrett , the fix is to ensure the API returns epoch time in seconds, and the plan is to gate existing users of this API into the current behavior with an option to ungate them if they would like to use the fixed behavior instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants