Webhooks - event.getDataObjectDeserializer().getObject.isPresent() suddenly returns false

1,573 views
Skip to first unread message

Steve Perkins

unread,
Mar 2, 2020, 6:06:37 PM3/2/20
to Stripe API Discussion
Hi there,

I've been using the EventDataObjectSerializer pattern from the Java code examples in the Stripe webhook documentation (e.g. https://stripe.com/docs/payments/handling-payment-events) for a few months now. It's been working as expected until an invoice.payment_succeeded request came through today. Now event.getDataObjectDeserializer().getObject().isPresent() returns false and ...getObject().get() returns null! The event object is definitely populated - if I dump it to the log I get the right event object structure and the nested StripeObject is what I'm expecting.

This is the actual code I'm using:

// Deserialize the nested object inside the event
EventDataObjectDeserializer dataObjectDeserializer = event.getDataObjectDeserializer();
StripeObject stripeObject = null;
if (dataObjectDeserializer.getObject().isPresent()) {
 stripeObject
= dataObjectDeserializer.getObject().get();
} else {
 
// Deserialization failed, probably due to an API version mismatch.
 
// Refer to the Javadoc documentation on `EventDataObjectDeserializer` for
 
// instructions on how to handle this case, or return an error here.
 LOG
.error("Stripe object deserialization failed for " + new Gson().toJson(dataObjectDeserializer.getObject()));
 badRequest
(ctx, "API version/lib mismatch");
 
return;
}


It seems pretty clear that the deserializer is failing for some reason, but not due to an API version mismatch. I've upgraded the API version in the console (2019-12-03) to the latest and upgraded my Stripe Java library to the latest (17.16.0) as well, but still have the same problem.

Any ideas? The only alternative to EventDatObjectSerializer I see is to parse the raw JSON, but that's discouraged.

This is the event object's JSON:
{
  "id": "evt_1GIM94DV8C5xxxxx",
  "object": "event",
  "api_version": "2019-09-09",
  "created": 1583185790,
  "data": {
    "object": {
      "id": "in_1GFRxxxxx",
      "object": "invoice",
      "account_country": "US",
      "account_name": "xxxxx",
      "amount_due": 10000,
      "amount_paid": 10000,
      "amount_remaining": 0,
      "application_fee_amount": null,
      "attempt_count": 2,
      "attempted": true,
      "auto_advance": false,
      "billing": "charge_automatically",
      "billing_reason": "subscription_cycle",
      "charge": "ch_1GIM92DV8C5Vxxxxx",
      "collection_method": "charge_automatically",
      "created": 1582493216,
      "currency": "usd",
      "custom_fields": null,
      "customer": "cus_GPo2pJgxxxxx",
      "customer_address": null,
      "customer_email": "xxxxx",
      "customer_name": null,
      "customer_phone": null,
      "customer_shipping": null,
      "customer_tax_exempt": "none",
      "customer_tax_ids": [
      ],
      "default_payment_method": null,
      "default_source": null,
      "default_tax_rates": [
      ],
      "description": null,
      "discount": null,
      "due_date": null,
      "ending_balance": 0,
      "footer": null,
      "hosted_invoice_url": "https://pay.stripe.com/invoice/acct_1xxxxx",
      "lines": {
        "object": "list",
        "data": [
          {
            "id": "sli_0baffb72385834",
            "object": "line_item",
            "amount": 10000,
            "currency": "usd",
            "description": "1 × xxxx (at $100.00 / month)",
            "discountable": true,
            "livemode": true,
            "period": {
              "end": 1584998807,
              "start": 1582493207
            },
            "plan": {
              "id": "plan_G6bxxxxx",
              "object": "plan",
              "active": true,
              "aggregate_usage": null,
              "amount": 10000,
              "amount_decimal": "10000",
              "billing_scheme": "per_unit",
              "created": 1572707921,
              "currency": "usd",
              "interval": "month",
              "interval_count": 1,
              "livemode": true,
              "metadata": {
                "max_requests": "100"
              },
              "nickname": "Flat Rate 1",
              "product": "prod_Gxxxxx",
              "tiers": null,
              "tiers_mode": null,
              "transform_usage": null,
              "trial_period_days": null,
              "usage_type": "licensed"
            },
            "proration": false,
            "quantity": 1,
            "subscription": "sub_GPoxxxxx",
            "subscription_item": "si_GPxxxxx",
            "tax_amounts": [
            ],
            "tax_rates": [
            ],
            "type": "subscription",
            "unique_id": "il_1GFRyWxxxxx"
          }
        ],
        "has_more": false,
        "total_count": 1,
        "url": "/v1/invoices/in_1GFRxxxxx/lines"
      },
      "livemode": true,
      "metadata": {
      },
      "next_payment_attempt": null,
      "number": "5FCC2xxxxx",
      "paid": true,
      "payment_intent": "pi_1GFSvNDxxxxx",
      "period_end": 1582493207,
      "period_start": 1579814807,
      "post_payment_credit_notes_amount": 0,
      "pre_payment_credit_notes_amount": 0,
      "receipt_number": "28xxxxx",
      "starting_balance": 0,
      "statement_descriptor": null,
      "status": "paid",
      "status_transitions": {
        "finalized_at": 1582496865,
        "marked_uncollectible_at": null,
        "paid_at": 1583185790,
        "voided_at": null
      },
      "subscription": "sub_Gxxxxx",
      "subtotal": 10000,
      "tax": null,
      "tax_percent": null,
      "total": 10000,
      "total_tax_amounts": [
      ],
      "webhooks_delivered_at": 1582493216
    }
  },
  "livemode": true,
  "pending_webhooks": 1,
  "request": {
    "id": "req_pj0sxxxxx",
    "idempotency_key": "4b1cxxxxx"
  },
  "type": "invoice.payment_succeeded"
}


Remi J.

unread,
Mar 2, 2020, 6:17:48 PM3/2/20
to api-d...@lists.stripe.com
Hello Steve,

While you mentioned this is not an API version issue, it's almost always the case with deserialization issues of events.

The stripe-java library is pinned to a specific API version today. This ensures that we have the correct types for each class (properties and parameters too). The idea is that if a property named A was a string and is now an object, we can release the change without breaking any integration.

When you deserialize an event, you need to make sure that the API version associated with that event matches the one that your library is pinned to. For example, the latest stripe-java is pinned to the latest API version (2019-12-03). If you try to deserialize an event that is formatted based on API version A with a version of the stripe-java library pinned to API version B, the deserialization will fail by default. This is to ensure you don't get crashes.

Even if you were to upgrade the API version on your account and use the latest version of the library, that would only work for new or future events. It would not change existing events that you already received. Even if you retrieve them via the API, the deserialization would still fail because of the API version mismatch. The event you mentioned for example is on API version 2019-09-09 and it would not work 

If this doesn't help, I'd recommend talking to our support team directly instead and providing them with detailed examples of events that you can not deserialize. You can contact them here: https://support.stripe.com/contact You can also talk to developers in #stripe on IRC on Freenode!

Hope this helps,
Remi

--
To unsubscribe from this group and stop receiving emails from it, send an email to api-discuss...@lists.stripe.com.

Steve Perkins

unread,
Mar 2, 2020, 6:51:17 PM3/2/20
to Stripe API Discussion
Hi Remi,

Thanks for responding! What you said makes sense to me. Where I'm stumbling on the API version matter is that the stripe-java library didn't change between last month (when this issue didn't happen) and today, and the version shown in the API console also didn't change until today. Can you think of anything that would fail this way?

It also makes sense that old events would be re-sent using the API version that was set at the time of their generation. I guess I was sort of hoping that the API version set in the console had somehow changed prior to the event generation and by upgrading the stripe-java library, I would once again be able to parse the request. That didn't happen but really, I'm glad it didn't! That kind of magic change would freak me out :(

I did contact Stripe support and was directed to this group pending contact from the developer support team. This issue hit me out of the blue today and I don't know what else I can do after quadruple-checking that the library and API versions. I'm entirely open to this being user error - please suggest some way to prove that! I'm not sure how else I can proceed.

Thank you,

Steve
To unsubscribe from this group and stop receiving emails from it, send an email to api-d...@lists.stripe.com.

Remi J.

unread,
Mar 2, 2020, 6:56:44 PM3/2/20
to api-d...@lists.stripe.com
Hey Steve,

Sorry about the confusion here! Since you already reached out to our support team, this would be the right place to get help as they can collect a lot more details from you about your code, your integration, your account and example events that are failing.

I'll have someone follow up with you directly there.

Best,
Remi

To unsubscribe from this group and stop receiving emails from it, send an email to api-discuss...@lists.stripe.com.

Steve Perkins

unread,
Mar 2, 2020, 7:11:05 PM3/2/20
to Stripe API Discussion
Hi Remi,

I appreciate it! Thomas from Stripe support got in touch with me just a few minutes ago. It looks like they're on the case!

Thank you,

Steve Perkins
To unsubscribe from this group and stop receiving emails from it, send an email to api-d...@lists.stripe.com.

Steve Perkins

unread,
Mar 2, 2020, 8:04:28 PM3/2/20
to Stripe API Discussion
Hi Remi,

Just wanted to update you - Thomas at Stripe support made a convincing case that the stripe-java version had been upgraded since the last webhook event, making it incompatible with the payment_succeeded event that was generated a little prior to upgrading the API version in the console. I'm going to monitor events next month and confirm. Thanks again for your help!

Steve Perkins
Reply all
Reply to author
Forward
0 new messages