Page MenuHomePhabricator

Failmail alert Validation error during recurring charge, in field: payment_method/id (PayPal)
Closed, ResolvedPublic

Description

Failmail search: "Failmail alert Validation error during recurring charge, in field: payment_method/id" "paypal"

Low priority since the first in weeks affecting paypal, however it's one of the many "Payment method has not been successfully stored" errors returned by Gravy unexpectedly without knowing exactly what it means; it was successfully stored in the past, so why the message? What changed? Why now it starts failing? etc.

Failmail logged error:

paypal. . {"recurring_payment_token":"4be102b9-c204-4305-9b13-e166443776a0","amount":1.75,"currency":"GBP","first_name":"xxx","last_name":"xxx","email":"xxx@xxx.co.uk","country":"GB","order_id":"250383642.2","installment":"recurring","description":"Wikimedia 877 600 9454","recurring":true,"user_ip":"xxx","processor_contact_id":null,"payment_service_id":"b4e49424-f463-4d0d-b05a-b427a4d21c95","fiscal_number":null}. Validation error during recurring charge, in field: payment_method/id. Message: Payment method has not been successfully stored. Current status: failed.. Response: {"type":"error","code":"bad_request","status":400,"message":"Request failed validation","details":[{"location":"body","pointer":"/payment_method/id","message":"Payment method has not been successfully stored. Current status: failed.","type":"value_error"}]}

Notes from investigation:

Event Timeline

From Gravy:

Why a transaction can capture while the payment method fails
When a donor pays with PayPal and we are also storing their account for future charges, that single PayPal order produces two separate results. The first is the payment itself, which > > > PayPal authorizes and captures. The second is the stored credential, the vaulted token that lets us charge that PayPal account again later without sending the donor back to PayPal. > > PayPal confirms these two things independently, and the second one can fail or simply never arrive while the first one succeeds. When that happens, the money is collected and the donor sees a completed donation, but on our side there is no reusable credential behind it. The transaction and the payment method are telling you about two different things, which is why they can disagree.
That is exactly what happened here.

What happened, step by step
On August 6 at 17:01:54 UTC the payment method was created together with transaction https://wikimedia.gr4vy.app/merchants/default/transactions/8ec54084-3184-42fc-95a7-> 8a9e164c18bf/overview. PayPal authorized and captured that payment 23 seconds later, at 17:02:17 UTC. The donation went through and there was nothing wrong with it.
The stored credential, however, was never completed. We opened it against the PayPal order and then waited for PayPal to confirm that the account had been vaulted. That confirmation > never reached us. Because of that the payment method stayed in a pending state, meaning it had been created and could be referenced by id, but it had never been validated as a usable stored credential.

When it changed to failed
On August 15 at 00:00:05 UTC.

How it changed
Not by PayPal, and not by anything sent from your side. It was our own housekeeping. We run a job that clears stored credentials still waiting for confirmation, and each payment service > defines how long we wait. PayPal's window is 8 days, so a credential opened on August 6 was cleared on August 15 and the payment method moved to failed. The reason we recorded > internally was that the storage process had expired.
Worth flagging, since it connects to the Trustly payment methods with May dates that Piero covered earlier: this window is set per payment service and is not consistent across all of > them today. PayPal has one, so you get a definitive failed status. Trustly US has none, so its pending credentials stay pending indefinitely. Aligning this is under review on our side and we > will come back to you on this.
Separately on webhooks: no webhook was emitted for this status change. We do not currently publish an event when a payment method is failed this way, so from your side there was no signal between August 15 and the next charge attempt.

The failed charge on September 6
With the payment method already in failed, a transaction was rejected up front with Payment method has not been successfully stored. Current status: failed. No attempt was sent to > > PayPal. This payment method will not become chargeable again, so that donor needs to re authorize.

What we recommend
The reliable guard is the one we mentioned earlier: check the payment method with GET /payment-methods/{id} before each recurring charge and only proceed when status is succeeded. That is the only status that guarantees a usable stored credential.

This seems one of those "payment method changed" error we cannot do anything about, if not discuss ways to improve it in the respective phab {T436299: Evaluate how to best handle changes to payment methods for recurring contributions in Gravy}

Closing it as a bug since the one thing we can do is to discuss ways to improve, if possible, this entire from from either the user or our chaos reporting perspective.

XenoRyet set Final Story Points to 2.