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

Duplicate entry stripe_id #1678

Closed
sebastianro92 opened this issue May 27, 2024 · 7 comments
Closed

Duplicate entry stripe_id #1678

sebastianro92 opened this issue May 27, 2024 · 7 comments

Comments

@sebastianro92
Copy link

Cashier Stripe Version

15.0

Laravel Version

10

PHP Version

8.3.6

Database Driver & Version

MYSQL, 8.0.36

Description

I use Stripe Webhooks, but when i cancelling a customer subscription and create a new subscription, received then next error:

[2024-05-27 00:05:04] local.ERROR: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'sub_1PKunxFd5Q4HlP154MBNJXW5' for key 'subscriptions.subscriptions_stripe_id_unique' (Connection: mysql, SQL: insert into subscriptions (type, stripe_id, stripe_status, stripe_price, quantity, trial_ends_at, ends_at, user_id, updated_at, created_at) values (default, sub_1PKunxFd5Q4HlP154MBNJXW5, incomplete, price_1Lu0DCFd5Q4HlP15qpPSBDWb, 1, ?, ?, 1, 2024-05-27 00:05:04, 2024-05-27 00:05:04)) {"exception":"[object] (Illuminate\Database\UniqueConstraintViolationException(code: 23000): SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'sub_1PKunxFd5Q4HlP154MBNJXW5' for key 'subscriptions.subscriptions_stripe_id_unique' (Connection: mysql, SQL: insert into subscriptions (type, stripe_id, stripe_status, stripe_price, quantity, trial_ends_at, ends_at, user_id, updated_at, created_at) values (default, sub_1PKunxFd5Q4HlP154MBNJXW5, incomplete, price_1Lu0DCFd5Q4HlP15qpPSBDWb, 1, ?, ?, 1, 2024-05-27 00:05:04, 2024-05-27 00:05:04)) at /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Connection.php:824)
[stacktrace]
#0 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Connection.php(783): Illuminate\Database\Connection->runQueryCallback()
#1 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Connection.php(576): Illuminate\Database\Connection->run()
#2 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Connection.php(540): Illuminate\Database\Connection->statement()
#3 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Query/Processors/Processor.php(32): Illuminate\Database\Connection->insert()
#4 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(3507): Illuminate\Database\Query\Processors\Processor->processInsertGetId()
#5 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(1982): Illuminate\Database\Query\Builder->insertGetId()
#6 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1333): Illuminate\Database\Eloquent\Builder->__call()
#7 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1298): Illuminate\Database\Eloquent\Model->insertAndSetId()
#8 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1137): Illuminate\Database\Eloquent\Model->performInsert()
#9 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php(342): Illuminate\Database\Eloquent\Model->save()
#10 /var/www/html/vendor/laravel/framework/src/Illuminate/Support/helpers.php(307): Illuminate\Database\Eloquent\Relations\HasOneOrMany->Illuminate\Database\Eloquent\Relations\{closure}()
#11 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php(339): tap()
#12 /var/www/html/vendor/laravel/cashier/src/Http/Controllers/WebhookController.php(83): Illuminate\Database\Eloquent\Relations\HasOneOrMany->create()
#13 /var/www/html/vendor/laravel/cashier/src/Http/Controllers/WebhookController.php(50): Laravel\Cashier\Http\Controllers\WebhookController->handleCustomerSubscriptionCreated()
#14 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Controller.php(54): Laravel\Cashier\Http\Controllers\WebhookController->handleWebhook()
#15 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(43): Illuminate\Routing\Controller->callAction()
#16 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Route.php(259): Illuminate\Routing\ControllerDispatcher->dispatch()
#17 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Route.php(205): Illuminate\Routing\Route->runController()
#18 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php(806): Illuminate\Routing\Route->run()
#19 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(144): Illuminate\Routing\Router->Illuminate\Routing\{closure}()
#20 /var/www/html/vendor/laravel/cashier/src/Http/Middleware/VerifyWebhookSignature.php(34): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#21 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Laravel\Cashier\Http\Middleware\VerifyWebhookSignature->handle()
#22 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(119): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#23 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php(805): Illuminate\Pipeline\Pipeline->then()
#24 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php(784): Illuminate\Routing\Router->runRouteWithinStack()
#25 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php(748): Illuminate\Routing\Router->runRoute()
#26 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php(737): Illuminate\Routing\Router->dispatchToRoute()
#27 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(200): Illuminate\Routing\Router->dispatch()
#28 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(144): Illuminate\Foundation\Http\Kernel->Illuminate\Foundation\Http\{closure}()
#29 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#30 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ConvertEmptyStringsToNull.php(31): Illuminate\Foundation\Http\Middleware\TransformsRequest->handle()
#31 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull->handle()
#32 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#33 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php(40): Illuminate\Foundation\Http\Middleware\TransformsRequest->handle()
#34 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Illuminate\Foundation\Http\Middleware\TrimStrings->handle()
#35 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php(27): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#36 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Illuminate\Foundation\Http\Middleware\ValidatePostSize->handle()
#37 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php(99): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#38 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance->handle()
#39 /var/www/html/vendor/laravel/framework/src/Illuminate/Http/Middleware/HandleCors.php(49): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#40 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Illuminate\Http\Middleware\HandleCors->handle()
#41 /var/www/html/vendor/laravel/framework/src/Illuminate/Http/Middleware/TrustProxies.php(39): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#42 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Illuminate\Http\Middleware\TrustProxies->handle()
#43 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(119): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#44 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(175): Illuminate\Pipeline\Pipeline->then()
#45 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(144): Illuminate\Foundation\Http\Kernel->sendRequestThroughRouter()
#46 /var/www/html/vendor/laravel/octane/src/ApplicationGateway.php(36): Illuminate\Foundation\Http\Kernel->handle()
#47 /var/www/html/vendor/laravel/octane/src/Worker.php(84): Laravel\Octane\ApplicationGateway->handle()
#48 /var/www/html/vendor/laravel/octane/bin/roadrunner-worker(54): Laravel\Octane\Worker->handle()
#49 /var/www/html/vendor/bin/roadrunner-worker(119): include('...')
#50 {main}

Steps To Reproduce

Cancel a customer subscription in Stripe Dashboard, then create a new customer subscription using the Stripe checkout portal.

@sebastianro92
Copy link
Author

Its recomendable add a delay in the listener to comprobe if the "customer.subscription.created" its ok?

image

@driesvints
Copy link
Member

I don't really understand this. There should only be a single customer.subscription.created event fired for each subscription. We already check for the stripe_id here: https://github.com/laravel/cashier-stripe/blob/15.x/src/Http/Controllers/WebhookController.php#L73

I assume you "retried" the webhook? But that still doesn't explains the error because there's enough time between the webhooks for handling this event without it being flaky.

Could you please provide a repo and then post exact steps to reproduce this one?

laravel new bug-report --github="--public"

@sebastianro92
Copy link
Author

sebastianro92 commented May 27, 2024

@driesvints Unfortunately, there is no exact way to replicate this issue as it does not always occur, but rather occurs randomly.

However, I'm almost sure that at some point the subscription that is created for the client is repeated twice; otherwise why would you get this error?

"Duplicate entry 'sub_1PL6sUFd5Q4HlP151A2WhXwH' for key 'subscriptions.subscriptions_stripe_id_unique'"

However, although I get this error, only one record is saved in the DB and this is fine, but there is a problem, when trying to save the second record and it generates the error, the "client.subscription.created" hook not is executed, causing my Application to fail because it does not detect the event and does not execute the functions that should be executed.

I hope it helps, but I share the error log that I just obtained a few minutes ago doing the process I mention.

  1. Cancel a customer subscription from the Stripe dashboard
  2. Then using the API to create a checkout session and add a new subscription for this customer
         $checkout_session = $stripeClient->checkout->sessions->create([
             'success_url' => config('access.STRIPE_REDIRECT_BACK'),
             'cancel_url' => config('access.STRIPE_REDIRECT_BACK'),
             'line_items' => [
                 [
                     'price' => config('access.LICENCE_PRICE_KEY'),
                     'quantity' => 1,
                 ],
             ],
             'mode' => 'subscription',
             'allow_promotion_codes' => true,
             'customer' => $customer->stripe_id,
         ]);
  1. Finally receive the Hooks, this is when possibly receive an error in "customer.subscription.created" -> "Integrity constraint violation: 1062 Duplicate entry 'sub_1PL6sUFd5Q4HlP151A2WhXwH' for key 'subscriptions.subscriptions_stripe_id_unique'" and the rest fails.

laravel.log

This is my handle listener

image

Is normal that when I create a new subscription for a customer, the "customer.subscription.updated" hook is executed?

This is a console.log from my Front dev.

image

And this is the total events when i created a new customer subscription

image

@driesvints
Copy link
Member

I'm sorry but I couldn't reproduce it using your example. You also seem to be working outside the context of Cashier with directly talking to the Stripe client. That's not supported I'm afraid. If you can post a clear code example that reproduces the issue I can have another look but right now I don't believe there's a major issue and this is most likely something specifically happening for you. I suggest to never work outside the context of Cashier.

And yes it's normal that updated events are sent together with the created events. Stripe updates the subscription after creating it.

@sebastianro92
Copy link
Author

Hi @driesvints maybe i have the same problem #1300 and #1307 ?

In my case is when add a new customer subscription and the error is randomly, i updated the checkout portal using cashier according your suggestions.

`
$customer = auth()->user();

    $checkout_session = $customer->newSubscription('default', 'my_price_key')
        ->allowPromotionCodes()
        ->collectTaxIds()
        ->checkout([
            'success_url' => config('access.STRIPE_REDIRECT_BACK'),
            'cancel_url' => config('access.STRIPE_REDIRECT_BACK'),
        ]);

    // * Redirect client to Stripe Checkout
    return response()->json($checkout_session->url);

`

@driesvints
Copy link
Member

I'm sorry @sebastianro92 but I'm going to leave things be. I just don't feel there's a widespread issue right now.

@endel
Copy link

endel commented Oct 4, 2024

I just experienced this issue, it turns out the issue (for me) was a bad migration of customer data. Let me explain.

  • My customer was leaving his company, and asked to move billing to a different user
  • I copied the stripe_id from his users database entry into the new user's entry.
  • ...moved other Stripe customer reference the database (cus_*)

When receiving the Stripe webhook, the $this->getUserByStripeId() method was still finding the first (wrong) user, instead of the new one. So I've nullified the stripe_id value from the first user and the issue was fixed.

image

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

No branches or pull requests

3 participants