#rocket_error

1 messages · Page 1 of 1 (latest)

warped drumBOT
scenic galeBOT
#

Below are links to other discussions we've had with you in the past week in case you want to review that information. If your question is related to one of these previous discussions, please provide a comprehensive summary of the current state and what you need help with now. We help many users simultaneously, so a summary allows us to resolve your issue as soon as possible.

warped drumBOT
#

👋 Welcome to your new thread!

⏲️ We'll be here soon! We typically respond in a few minutes, but in some cases we might need a bit more time (e.g., server's busy, you've got a complex question, etc.).

⏱️ We close idle threads, which makes them read-only. Once a thread is closed it won't be reopened, but you can start a new thread if you have another question.

🔗 This thread will always be available, even after it's closed. You can find it again using Discord's search, or you can save this link: https://discord.com/channels/841573134531821608/1248428058524778558

📝 Have more to share? Add details, code, screenshots, videos, etc. below.

rotund perch
#

error logs in vercel

wild ginkgo
#

Could you summarize the last state of yesterday thread? Were you able to find the information you want in your webhook function?

rotund perch
#

so I was able to resolve what I thought was the root cause of the issue

#

essentially it seems like there was an error with JSON.parse

#

so I resolved that

#

however it appears there's some other cause of this error

#

with the error being multiple attempts to capture a paymentintent

#

another instance of the error just happened

#

all I know is that the webhook endpoint is getting a 500

#

request ID is req_CJj0k970tijcZl

#

same issue with "This PaymentIntent could not be captured because it has already been captured."

wild ginkgo
#

It was originally captured by req_CY54wZFwsCF6nx

rotund perch
#

yeah i'm unsure what's causing the initial failure

wild ginkgo
#

You mean the initial capture?

rotund perch
#

I guess?

#

as in

#

why the initial capture failed which then led to these recapture requests

#

it only says 504 gateway timeout on my vercel logs

rotund perch
wild ginkgo
#

It's succeeded in Stripe log so could be just the connection issue

#

Can you reproduce it constantly?

rotund perch
#

no not constantly

#

it only happened once

#

there was one other instance of an error

#

but i think that may have been from something else

#

I think the other instance was just due to a failed recapture last night that tried again

#

here is my endpoint code, wondering if anything catches your eye for a potential cause

#

so the error occurred one other time which was earlier today at 2pm EST

#

just a generic 500 error on vercel's end, nothing more that I can use to figure out

#

req_4CADZQ4Q9XPbQn is the id

wild ginkgo
#

Same that it was captured before on req_lojGtfXjrzr7J8

#

You would want to look at what happened on req_lojGtfXjrzr7J8. None of it and req_4CADZQ4Q9XPbQn was at 2pm EST

rotund perch
wild ginkgo
#

So req_lojGtfXjrzr7J8 was the first time you captured the PI and it was succeeded

#

Then you retried multiple time, including req_4CADZQ4Q9XPbQn and it failed because the PI is already captured

#

Looks like you are recapturing the same PI, which leads to the error

rotund perch
#

I don't understand how that could happen though

#

I only have one request to capture the payment intent

#
const paymentIntent = await stripe.paymentIntents.capture(payment_intent_id);
  if (paymentIntent.status !== "succeeded") {
    return NextResponse.json({
      error: `Payment failed`,
    });
  } else {
    //Send email with codes
    await resend.emails.send({
      ...
    });
    return NextResponse.json({ success: true });
  }```
#

this is the very end of my endpoint

#

what could cause it to recapture again?

#

ah so it seems like the task is timing out?

#

Task timed out after 15.02 seconds

#

strange that is later on

#

so that's not necessarily the issue

#

so I'm looking at

#

req_CY54wZFwsCF6nx

#

this is the initial capture for the error from today

wild ginkgo
#

Does this code run repeatly with a same PaymentIntent Id?

rotund perch
#

when looking in the vercel logs, there appear to be two requests to the stripe endpoint for some reason

rotund perch
wild ginkgo
#

I see the code, but you would want to add log to log the time, and the payment intent id before the capturing logic

#

ie if we look at pi_3POSohHvAVLYAKEc1UmwGdcc

  1. The first succeded request is req_lojGtfXjrzr7J8 on 2024-06-05 23:00:34
  2. Next failed request is req_DxaRDk4xdXumcp on 2024-06-05 23:00:53
  3. Next is req_FaoKzoWxllF7ET on 2024-06-06 00:01:59
  4. Next is req_R1e0lgH1CE0XhU on 2024-06-06 03:59:48
  5. Next is req_4CADZQ4Q9XPbQn on 2024-06-06 18:09:54
#

Time is UTC

#

The times are quite different. Looks like your code could have been trying to capture in different places

#

You can copy and paste all the request id above to your Dashboard search and see the history

rotund perch
#

when a request fails it retries with increasing intervals which is what it appears to be

wild ginkgo
#

retries to which webhook event?

rotund perch
#

wait

#

if you don't mind

#

can we examine req_CY54wZFwsCF6nx

#

I can't see the vercel logs for the request you mentioned

#

so I'm cross referencing stripe and vercel logs for req_CY54wZFwsCF6nx

wild ginkgo
rotund perch
#

I can see the successful request is 7:27:09

#

when I go on vercel logs

#

I see two requests for some reason

#

one at 7:27:07 which is successful

#

and then another at 7:27:08 which throws a 504

#

gateway timeout

wild ginkgo
#

Ok first, when you received checkout.session.completed, did you response 200 to Stripe?

#

If you don't we will keep retrying to send it to you

rotund perch
wild ginkgo
#

and you will end up with calling the same logic multiple times

rotund perch
#

I believe so because the first one has a 200 status right?

#

and also most payments appear to work

wild ginkgo
#

I am looking at pi_3POSohHvAVLYAKEc1UmwGdcc, and its checkout.session.completed is evt_1POSomHvAVLYAKEcck1qBpUt which hasn't received a 200 response

#

The recommended practice is always respond 200 to Stripe first, before doing your logic. Because we have some timeout to mark the deliver as failed

rotund perch
#

so I should respond 200 at the top?

#

not sure how I could respond 200 before I finish my logic

wild ginkgo
#

Good question. The ideal way is to pushing the event to some internal queue, and process the queue later, then return 200. When you process the queue, you can call capture API

#

But before going that far, could you make sure to just respond 200 in the end of your function?

#

Like, no matter which route it goes, respond 200 in the end

rotund perch
#

ok added that

#

i don't understand why this is happening for this request and not every other request

#

a large majority of them all work

#

is there a possibility that a paymentIntent will be captured successfully but not give a status of succeeded?

#
const paymentIntent = await stripe.paymentIntents.capture(payment_intent_id);
  if (paymentIntent.status !== "succeeded") {
    return NextResponse.json(
      {
        error: `Payment failed`,
      },
      { status: 200 }
    );
  } else {
    //Send email with codes
    await resend.emails.send({
      ...
    });
    return NextResponse.json({ success: true }, { status: 200 });
  }```
#

the issue i'm encountering is that the email isn't being sent even though it seems the payment intent was indeed captured

#

which makes me think that somehow, the paymentIntent was captured but it didn't return a status of "succeeded"

wild ginkgo
#

So you only respond back to Stripe if the call to capture PaymentIntent succeeded. Tha’s true for most case, but if you sent out the request then connection lost, your code timeout but Stripe still receive the request and process to capture

#

You may want to move the email sending to when you received payment_internt.captured instead

#

that guaranteed the PI is captured and isn’t related to the API call earlier on checkout.session.completed

rotund perch
#

so listen for a different webhook event?

#

it seems payment_intent.captured doesn't exist

#

do you mean payment_intent.succeeded?

wild ginkgo
#

oh sorry, 1 min

#

I thi k it’s payment_intent.amount_capturable_updated

#

could you start a stripe listen in Stripe CLI and listen to all event

#

then send a capture API in Test mode

#

to inspect which event it sends?

rotund perch
#

the CLI hasn't been working for me

wild ginkgo
#

Why? It’s an useful tool to test webhook

rotund perch
#

i'm having issues setting up: I added the path of stripe.exe to my path environment variables but stripe isn't recognized as a command

#

but besides that, why would you say it's amount capturable vs succeeded

wild ginkgo
#

I think their timing could be different. I can test for you in 30mins ish but I really recommend to setup Stripe CLI and test in Test mode

rotund perch
#

I've tried, I just can't get the command to work

rotund perch
#

I know it's very valuable and I can't thank you enough for your time

#

I just ran

#

the stripe cli

#
2024-06-06 22:13:37   --> payment_intent.amount_capturable_updated [evt_3POsJ8HvAVLYAKEc0e3NpbjA]
2024-06-06 22:13:37   --> payment_intent.created [evt_3POsJ8HvAVLYAKEc0QvGsmaY]
2024-06-06 22:13:37   --> charge.succeeded [evt_3POsJ8HvAVLYAKEc0IapNmeE]
2024-06-06 22:13:38   --> checkout.session.completed [evt_1POsJAHvAVLYAKEcoCXHvZWJ]```
#

here is what I got

#

the flow

#

by the way, my endpoint code already listens for the checkout.session.completed event

wild ginkgo
#

Oh you ran the Stripe CLI

#

okie then when you capture the PI, what do you receive?

rotund perch
#

everything works as intended

#

no errors

#

I setup the flags to forward it to my localhost

#

so that it can trigger my endpoint

wild ginkgo
#

Yeah okie then let's capture the PI, which webhook event you get?

rotund perch
#

uhh what do you mean

rotund perch
#

but for my endpoint, I listen for the checkout session completed event

wild ginkgo
#

Okie I see, no worry

#

So before capture you will get payment_intent.amount_capturable_updated

#

after capture you will get payment_intent.succeeded

#

So you can move the email sending logic over when received payment_intent.succeeded

rotund perch
#

oh I don't think I got payment_intent.succeeded

wild ginkgo
#

And keep the calling Capture API logic on checkout.session.completed

rotund perch
#

when I listened for all events I don't think I got an event for payment_intent.succeeded

#

oh wait let me try again

#

because I didn't capture

wild ginkgo
#

Yeah

rotund perch
#

hm

#

for the flow, I don't know if I can separate it to a different endpoint

#

since I'm checking for something in the database and then removing it

#

I don't want to capture the payment intent first because what if the item in the database doesn't have enough quantity?

wild ginkgo
#

You can keep your flow of logic until calling Capture PaymentIntent API, in checkout.session.completed, no?

#

Only the logic of sending email, move it over to payment_intent.succeeded

rotund perch
#

but I need variables declared in the code

#

products

#

for example

#

I fetch from the database and then send at the end in the email

#

unless there's a way to forward that data to the payment_intent.succeeded endpoint but I don't think so

#

also I still don't know why it's failing in the first place

#

i've only started encountering this recently

#

is the payment intent capture succeeding but somehow not returning the response in time?

wild ginkgo
#

Let's put the "why it happen" part aside. It is the connection and it could happen sometimes, depends on the network between your node and Stripe server

#

You can fetch the products from the database again, when you receive payment_intent.succeeded, no? It's a different thing

rotund perch
#

yes but doesn't that seem extremely redundant

#

because i'm doing all the fetching and whatnot already in the checkout.session.completed

#

and then I would need to fetch from the database again

rotund perch
#

is there a way for me to retrieve the lineItems for the payment_intent.succeded event?

wild ginkgo
#

Yeah you can call Retrieve PaymentIntent and expand what it's not already for you in the event body

rotund perch
#

could you please provide an example

wild ginkgo
rotund perch
#

so I retrieve the paymentId from the event

#

and then make a call to retrieve that paymentIntent using the id

#

and then expand?

#

the payment intent object doesn't seem to have a line_items property, would that still work?

wild ginkgo
#

On the request to retrieve, expand the line_items.xxx depends on what you want to retrieve

rotund perch
#

hm okay let me try that

warped drumBOT
rotund perch
#

it doesn't seem like I can expand line_items on the paymentIntent

#
const paymentIntentId = event.data.object.id;
  const paymentIntent = await stripe.paymentIntents.retrieve(paymentIntentId, {
    expand: ["line_items"],
  });

  console.log(paymentIntent);```
past atlas
rotund perch
#

how can I access that from the payment_intent.succeeded event though

#

also thank you to orakaro for the hours of assistance 🙏

past atlas
#

why do you want to access it from the payment_intent.succeeded event? you should listen for the checkout.session.completed event

rotund perch
#

uh

#

well I was told to

#

there's a lot of stuff above

#

basically

past atlas
#

you can listen to more than 1 event

rotund perch
#

uh

#

yes but I'm listening to it from a different route

#

so what is happening is it appears that my webhook endpoint is sending a request to capture

#

but for some reason, my code to send an email isn't executing

rotund perch
#

this has worked perfectly fine until the past two days

#

when I started getting 500 errors for some odd reason

#

these are the vercel logs for an instance of the error i'm talking about

#

and this is connected to req_CY54wZFwsCF6nx

#

so it is successfully captured, but for some reason, the endpoint gets called again

past atlas
#

have you tried walking through your code step by step? to see why the endpoint gets called again?

rotund perch
#

I have, I don't understand why it would

#
const paymentIntent = await stripe.paymentIntents.capture(payment_intent_id);
  if (paymentIntent.status !== "succeeded") {
    return NextResponse.json(
      {
        error: `Payment failed`,
      },
      { status: 200 }
    );
  } else {
    //Send email with codes
    await resend.emails.send({
      ...
    });
    return NextResponse.json({ success: true }, { status: 200 });
  }```
#

this is the very end of my endpoint codew

#

which also leads me to ask, why wasn't my email code executed. was it something with the paymentIntent capture?

#

because if there was an initial capture request for the payment intent that succeeded, then my code to send the email should have executed

#

but it hasn't

#

also for context, i've had close to 20 payments today, but this error has only occurred once

#

so it's not something that I was able to reproduce consistently either, i'm not sure why it's happening

#

it was also working fine before for the past few months until 2 days ago

past atlas
#

to clarify, the problem with 500 error code responses is solved already?

rotund perch
#

not sure

#

I still don't know why it's happening

past atlas
#

what do you mean? Are you or are you not receiving a 500?

rotund perch
#

as in

#

I have received a 500

#

but only for a singular payment

#

and I'm unsure why

#

I cannot reproduce more 500s

past atlas
#

so lets take this one step at a time

#

what's the request id where you received 500 in response for?

rotund perch
#

I just received one right now actually

#

I'll send that one

#

here is the event ID

#

evt_1POpi3HvAVLYAKEcIa8sjLDd

#

and then here is the error request ID: req_hM81fSHL5EyBTQ

#

this is all I see in my vercel error logs

#

^ above includes the initial successful capture request

#

so there's an initial request to capture the paymentIntent that succeeds

#

but i'm not sure why another one is being sent

past atlas
#

again, lets solve the problem one step at a time and focus on the 504 first

rotund perch
#

okay what is your proposed first step I should do?

past atlas
#

From Stripe's end, we receive a 504. The headers seem to indicate that you're also using Cloudflare. So it seems like somewhere in your server along the way, a 500 / 504 is being returned. The first step you need to do is to trace where exactly the 500 is being sent/returned from. It's not possible for us to help you track / trace that down. You may need to trace through your network logs to identify if it's being returned by your app / vercel / or possibly further downstream. Then if it's from your app, you need to identify the exact line of code that is causing this

Since 504 (Gateway Timeout) status code indicates that the server, while acting as a gateway or proxy, did not receive a timely response from an upstream server - like what Orakaro said, you should return 200 first before performing any complex logic. I don't see the changes reflected in codeshare though

rotund perch
#

the codeshare expired, I'll send an updated one with the current code

#

ah never mind, I've updated it

#

so yes, those changes weren't yet present in the 504

#

I have also turned off cloudflare proxying

past atlas
#

if you received another 500 after you've made those changes, my steps still apply

rotund perch
#

this was a pure 500, not 504

past atlas
#

it may be a 500 in your logs, what Stripe sees is a 504

rotund perch
#

for this most recent error?

#

then perhaps it is cloudflare

#

say I wanted to go the route of returning 200 first

#

how could I return a response but then execute after?

past atlas
#

ah sorry, i was looking at an older attempt. Yes, the latest attempt is 500

rotund perch
#

mm so the 504 is likely because of cloudflare

#

if this helps, I had added console logs before each instance of returning a response

#

and there was a payment 3 minutes before the 500 error I mentioned above

#

and it seems there is a difference

past atlas
#

you need to implement your own logic to store the requests from Stripe, then execute them in order

rotund perch
#

so this payment the checkout 200'd and also displayed the console log message I had written

#

however the one that errors out doesn't display any console log message

#

would you have any ideas as to whether or not this might be relevant

past atlas
#

nobody will know why your app is returning a 500. You need to add additional logging, walk through your code to identify the exact line that is causing issues

rotund perch
#

does anything in the codeshare catch your eye? I've added logs before each response, which also returns a 200 no matter what happens

past atlas
#

why are you returning 200 if the request doesn't have a signature?

rotund perch
#

should I change that to a 403?

past atlas
#

no, you shouldn't change it to a 403. Orakaro said to always respond with 200 upon receipt of the request. How does returning 200 if the request doesn't have a signature match with what Orakaro said?

#

so if the request has a signature, it's not going to respond with 200 at that point right?

rotund perch
#

because returning a response would end the execution of the rest of the code

#

so if it has a signature it would just proceed with the rest of the code?

#

am I understanding it wrong

#

if you look at every instance where I return a response, there is a status 200

past atlas
#

You need to rework your entire server side logic to be able to store the request for later processing, and respond to the request with 200. This isn't something that can be achieved with a single line of code

putting aside returning 200 first. You need to track down where exactly in your code there is an error which results in 500 being returned

rotund perch
#

so

#

is the 200 related to the 500?

past atlas
#

again, i don't know. You need to track / debug your own code for this

rotund perch
#

I see

#

other than the 200 issue

#

do you see anything else that raises suspicion?

#

would the api version be a potential cause?

past atlas
#

no, the api version is not a cause

rotund perch
#

also, is there anyway to prevent stripe from retrying the event?

#

it seems like the error I got was actually connected to the 504 from a while back

past atlas
#

Stripe retries an event when we don't receive a 2XX response

rotund perch
#

hmm

#

would adding a line towards the beginning to check if a payment intent status is "succeeded" help resolve that?

past atlas
#

you can try

rotund perch
#

will do

#

okayt

#

so after adding that check at the beginning

#

I was able to resolve that recurring 500

#

so far with the revised code I haven't encountered a 500 yet

#

I guess I will wait and see if the issue arises again

#

perhaps cloudflare proxy was the root cause

#

thank you for your assistance orakaro and alex, it's greatly appreciated