question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Duplicate event errors when receiving duplicate webhooks from Stripe

See original GitHub issue

Hi,

For a while now, we’ve been getting duplicate event errors on our webhook.

This is the full traceback and error:

File "/app/.heroku/python/lib/python3.6/site-packages/django/db/backends/utils.py" in _execute
 84.                 return self.cursor.execute(sql, params)

The above exception (duplicate key value violates unique constraint "djstripe_event_stripe_id_key"
DETAIL:  Key (id)=(evt_1HJr21IYqDxf18x89cVYyoRP) already exists.
) was the direct cause of the following exception:

File "/app/.heroku/python/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
 34.             response = get_response(request)

File "/app/.heroku/python/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
 115.                 response = self.process_exception_by_middleware(e, request)

File "/app/.heroku/python/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
 113.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/app/.heroku/python/lib/python3.6/site-packages/sentry_sdk/integrations/django/views.py" in callback
 52.             return old_callback(*args, **kwargs)

File "/app/.heroku/python/lib/python3.6/site-packages/sentry_sdk/integrations/django/views.py" in callback
 52.             return old_callback(*args, **kwargs)

File "/app/.heroku/python/lib/python3.6/site-packages/django/views/generic/base.py" in view
 71.             return self.dispatch(request, *args, **kwargs)

File "/app/.heroku/python/lib/python3.6/site-packages/django/utils/decorators.py" in _wrapper
 45.         return bound_method(*args, **kwargs)

File "/app/.heroku/python/lib/python3.6/site-packages/django/views/decorators/csrf.py" in wrapped_view
 54.         return view_func(*args, **kwargs)

File "/app/.heroku/python/lib/python3.6/site-packages/django/views/generic/base.py" in dispatch
 97.         return handler(request, *args, **kwargs)

File "/app/.heroku/python/lib/python3.6/site-packages/djstripe/views.py" in post
 35.         trigger = WebhookEventTrigger.from_request(request)

File "/app/.heroku/python/lib/python3.6/site-packages/djstripe/models/webhooks.py" in from_request
 117.             raise e

File "/app/.heroku/python/lib/python3.6/site-packages/djstripe/models/webhooks.py" in from_request
 103.                     obj.process(save=False)

File "/app/.heroku/python/lib/python3.6/site-packages/djstripe/models/webhooks.py" in process
 187.         self.event = Event.process(self.json_body)

File "/app/.heroku/python/lib/python3.6/site-packages/djstripe/models/core.py" in process
 1353.             ret = cls._create_from_stripe_object(data)

File "/app/.heroku/python/lib/python3.6/site-packages/djstripe/models/base.py" in _create_from_stripe_object
 436.             instance.save(force_insert=True)

File "/app/.heroku/python/lib/python3.6/site-packages/django/db/models/base.py" in save
 741.                        force_update=force_update, update_fields=update_fields)

File "/app/.heroku/python/lib/python3.6/site-packages/django/db/models/base.py" in save_base
 779.                 force_update, using, update_fields,

File "/app/.heroku/python/lib/python3.6/site-packages/django/db/models/base.py" in _save_table
 870.             result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)

File "/app/.heroku/python/lib/python3.6/site-packages/django/db/models/base.py" in _do_insert
 908.                                using=using, raw=raw)

File "/app/.heroku/python/lib/python3.6/site-packages/django/db/models/manager.py" in manager_method
 82.                 return getattr(self.get_queryset(), name)(*args, **kwargs)

File "/app/.heroku/python/lib/python3.6/site-packages/django/db/models/query.py" in _insert
 1186.         return query.get_compiler(using=using).execute_sql(return_id)

File "/app/.heroku/python/lib/python3.6/site-packages/django/db/models/sql/compiler.py" in execute_sql
 1335.                 cursor.execute(sql, params)

File "/app/.heroku/python/lib/python3.6/site-packages/raven/contrib/django/client.py" in execute
 127.             return real_execute(self, sql, params)

File "/app/.heroku/python/lib/python3.6/site-packages/sentry_sdk/integrations/django/__init__.py" in execute
 489.             return real_execute(self, sql, params)

File "/app/.heroku/python/lib/python3.6/site-packages/django/db/backends/utils.py" in execute
 67.         return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)

File "/app/.heroku/python/lib/python3.6/site-packages/django/db/backends/utils.py" in _execute_with_wrappers
 76.         return executor(sql, params, many, context)

File "/app/.heroku/python/lib/python3.6/site-packages/django/db/backends/utils.py" in _execute
 84.                 return self.cursor.execute(sql, params)

File "/app/.heroku/python/lib/python3.6/site-packages/django/db/utils.py" in __exit__
 89.                 raise dj_exc_value.with_traceback(traceback) from exc_value

File "/app/.heroku/python/lib/python3.6/site-packages/django/db/backends/utils.py" in _execute
 84.                 return self.cursor.execute(sql, params)

Exception Type: IntegrityError at /stripe/webhook/
Exception Value: duplicate key value violates unique constraint "djstripe_event_stripe_id_key"
DETAIL:  Key (id)=(evt_1HJr21IYqDxf18x89cVYyoRP) already exists.

A consequence of that is that, although Djstripe objects are unpdated and kept in sync fine, our webhook handlers are not triggering. For example, if we have an action set up when a subscription is moved to past_due, like so:

@webhooks.handler('customer.subscription.updated')
def subscription_past_due(event, **kwargs):
    obj = event.data['object']
    prev_attrs = event.data['previous_attributes']
    previous_status = prev_attrs.get('status', None)
    if previous_status and obj['status'] == 'past_due':
       # do stuff

it never executes, although it works fine when calling the function manually with the relevant customer.subscription.updated event.

Environment:

  • dj-stripe version: 2.3.0
  • Your Stripe account’s default API version: 2020-08-27
  • Database: Postgres 12.1
  • Python version: 3.6.0
  • Django version: 2.2.6

Issue Analytics

  • State:open
  • Created 3 years ago
  • Comments:10 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
RaceDirectorsHQcommented, Sep 16, 2020

So I did two things that seem to have fixed both the duplicate event error and the webhooks not being triggered issue.

  1. I imported my webhook handlers file in my app’s AppConfig like so:
class PaymentsConfig(AppConfig):
    name = 'payments'

    def ready(self):
        import payments.signals
        import payments.webhooks

I’m still not sure that’s really needed there… I haven’t come across such an instruction in the docs or elsewhere, but I just tried it because signals need to be imported that way and I guess webhooks work similarly, so it was worth a try.

  1. I upgraded my Heroku plan from the hobby plan that allows the server to sleep between requests to a paid one that doesn’t. I noticed on my Stripe webhook dashboard that several events were timing out, which was probably because of the Heroku server taking time to come online. Since upgrading the server plan to one that doesn’t sleep, all events come through without timeouts - and without duplicates.

It could be the case that somehow previously the event was being received at the webhook endpoint but without sending back a 200 response which may have caused Stripe to try again - hence the duplicate.

I’ll keep an eye over the next few days, but it looks like these two tweaks may have taken care of my issues.

Thanks again for the help, @jleclanche

0reactions
arnav13081994commented, Sep 1, 2022

@jleclanche This issue no longer seems relevant. Can be closed?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Best practices for using webhooks | Stripe Documentation
Handle duplicate events. Webhook endpoints might occasionally receive the same event more than once. We advise you to guard against duplicated event receipts...
Read more >
Stripe Webhooks. Dealing with multiple webhook events
We advise you to guard against duplicated event receipts by making your event processing idempotent. One way of doing this is logging the...
Read more >
webhook event called multiple times for single event
As for the duplicate delivery, it should be rare but it is possible that it happens. The idea is that you might think...
Read more >
Rework handling of Stripe webhooks · Issue #512 - GitHub
Webhook endpoints may occasionally receive the same event more than once. We advise you to guard against duplicated event receipts by making ...
Read more >
Database duplicate entry error after stripe webhook request
Does someone know how to resolve this issue? Our stripe webhook logs show payment_succeeded events as failing.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found