#daartanian_connect-embedded
1 messages ยท Page 1 of 1 (latest)
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.
- daartanian_api, 14 hours ago, 48 messages
๐ Welcome to your new thread!
โฒ๏ธ We'll be here soon! Typically we respond in a few minutes, but sometimes we might take a bit longer if the server is busy or if you have a particularly tricky question.
โฑ๏ธ We close idle threads, which makes them read-only. Once a thread is closed it won't be reopened, but you can always 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/1273760922929860703
๐ Have more to share? Add more details, code, screenshots, videos, etc. below.
sup @undone whale ๐๐ป
Hey @vagrant bison ! I'm happy to help but I need you to clearly ask your summarized question. I won't be able to go and read the thread to get the state (see the message from the bot above)
Ah. Hmm... ok. I can give more context.
It started with that happening in my code ๐๐ป
So we ended up moving the ConnectComponentProvider wrapper closer to the components that seemed to be having issues. That seemed to clear up that error.
So it went from this (the state from the video):
to this:
Do you have a 2 or 3 sentences summary in text as human?
And that seemed to clear up that issue. But in the back of my head I remembered an issue popping up that caused me to back the ConnectComponentProvider all the way back to the base level
in text as human
do you just mean not a video?
I mean I will watch that video but it'd help to have a real summary in words in text that I can read in 10 seconds to get an understanding of what you're even asking. You jumped deep in screenshot of something I don't really follow with no context yet. I'm trying to get my bearings, we have dozens of products and APIs
Cool, cool. I can do that.
oh boy an 8 minutes video
so yeah let's pause on that and wait for a clear summary if possible
I am using Stripe Connect integrated into our software.
I was having issues where when I was trying to load a component underneath the ConnectComponentProvider wrapper (as you guys instruct to do in your docs), I was getting an error saying it couldn't find the ConnectComponentProvider.
Working together with another suport dev last night, we moved the ConnectComponentProvider closer to where the Stripe Connect Component is being called. But now there is an issue where it is saying, when I try and switch from one Stripe Connect Component to another one inside of the ConnectComponentProvider wrapper:
`"cannot_create_account_session"
"You tried to claim an account session that has already been claimed."
and it doesn't load.
Okay what exact doc are you following and which part of your code exactly is showing that new error
daartanian_connect-embedded
let me find the right docs for you
Sure and if you can share the relevant part of the code where you switch the component, that'd help. My guess is that you reinitializing something with a cached AccountSession client_secret
This is, I think, what I original built this thing with: https://docs.stripe.com/connect/embedded-onboarding?shell=true&api=true
let me get you some code
This is where people are directed to a zero state if we can't find a Stripe Connect account Id associated with them. There is a Sign Up button inside of ManageBillingZeroState that they click and we create an account for the user with a call to that endpoint outlined in Step 1 of that document:
const ManageBilling = () => {
const userConfig = useUserConfig();
const partnerId = String(userConfig?.partnerRecord[0]?.id);
const [isUserSignedUpToStripe, setIsUserSignedUpToStripe] = useState(Boolean(
userConfig?.partnerRecord[0]?.stripe_connected_account_id,
));
const [stripeAccountId, setStripeAccountId] = useState<string>(userConfig?.partnerRecord[0]?.stripe_connected_account_id || '');
const handleStripeSignUp = ({
accountIdForStripe,
userSignedUpToStripeValue,
}: HandleStripeSignUpParams) => {
setStripeAccountId(accountIdForStripe);
setIsUserSignedUpToStripe(userSignedUpToStripeValue);
const domain = window.location.hostname;
const queryKey = ['config', { domain }];
guardianQueryClient.invalidateQueries(queryKey);
};
const getBillingContent = () => {
switch (isUserSignedUpToStripe) {
case true:
return <StripeContent stripeAccountId={stripeAccountId} />;
default:
return (
<ManageBillingZeroState
handleStripeSignUp={handleStripeSignUp}
partnerId={partnerId}
/>
);
}
};
return (
<WidgetWrapper headerIcon={CreditCardIcon} title="Billing">
{getBillingContent()}
</WidgetWrapper>
);
};
export default ManageBilling;
I didn't include imports for the sake of discords text limits
Okay, which exact part of that code is raising the exact error you mentioned?
Good question. So inside of the StripeContent, we have this code:
const StripeContent = ({ stripeAccountId }: StripeOnboardingProps) => {
const [currentStripeComponent, setCurrentStripeComponent] = useState<StripeComponent | undefined>();
const {
hasBeenOnboarded,
isPending: isRetrieveAccountPending,
error: retrieveAccountError,
} = useStipeRetrieveAccount(stripeAccountId);
useEffect(() => {
switch (hasBeenOnboarded) {
case true:
setCurrentStripeComponent(StripeComponent.Dashboard);
break;
case false:
setCurrentStripeComponent(StripeComponent.Onboarding);
break;
default:
// We don't want to log an error during the re-renders on loading
if (!isRetrieveAccountPending) {
consoleLogger.errorMessage({ message: 'No onboarding status found' });
}
}
}, [hasBeenOnboarded]);
const handleOnboardingExit = async () => {
// The waiting is due to a bug in Stripe's components,
// it needs time to know onboarding has been completed
await delay(2000);
setCurrentStripeComponent(StripeComponent.Dashboard);
};
const getStripeContent = () => {
switch (currentStripeComponent) {
case StripeComponent.Dashboard:
return (
<StripeDashboard />
);
case StripeComponent.Onboarding:
return (
<ConnectAccountOnboarding onExit={handleOnboardingExit} />
);
default:
return <LoadingState />;
}
};
return (
<div className="text-center">
<StripeConnectWrapper stripeAccountId={stripeAccountId}>
{getStripeContent()}
</StripeConnectWrapper>
</div>
)
}
Its in this step that I get the error. When the UI tries to load the ConnectAccountOnboarding
It errors on this claim endpoint: https://api.stripe.com/v1/account_sessions/claim
okay, sorry I struggle with React nad that's so much code without a clear "this exact line is the issue"
where in your code do you pass the AccountSession's client_secret?
Yea, sorry, the Stripe stuffed is pretty weaved in to React code here. That <StripeConnectWrapper /> is where that happens:
import React, { useEffect } from 'react';
import { loadConnectAndInitialize } from '@stripe/connect-js';
import { ConnectComponentsProvider } from '@stripe/react-connect-js';
const StripeConnectWrapper = ({ stripeAccountId, children }: StripeConnectComponentWrapperProps) => {
const appConfig = getConfig();
const thisIsADevelopmentEnvironment = isThisADevelopmentEnvironment();
const [stripeKey, setStripeKey] = React.useState<string>('');
const { stripe_publishable_key, stripe_publishable_test_key } = appConfig.global_configuration;
useEffect(() => {
setStripeKey(thisIsADevelopmentEnvironment ? stripe_publishable_test_key : stripe_publishable_key);
}, []);
if (!stripeAccountId) return <div>{children}</div>;
const {
clientSecret,
isPending: isFetchClientSecretPending,
error: fetchClientSecretError,
} = useStipeFetchClientSecret(stripeAccountId);
if (isFetchClientSecretPending) return <LoadingState />;
if (fetchClientSecretError) {
return (
<ErrorState
error={fetchClientSecretError}
description="Please try again and contact support if this continues."
/>
);
}
const connectInstance = loadConnectAndInitialize({
publishableKey: stripeKey,
fetchClientSecret: () => clientSecret,
appearance: {
variables: {
// This is the same color as tailwind color admin-portal-blue
colorPrimary: '#C8B56E', // optional appearance param,
},
},
});
return (
<div className="text-center">
<ConnectComponentsProvider connectInstance={connectInstance}>
{children}
</ConnectComponentsProvider>
</div>
);
};
export default StripeConnectWrapper;
okay that helps. Damn I hate React lol
In this file ๐๐ป you can see this chunk:
const connectInstance = loadConnectAndInitialize({
publishableKey: stripeKey,
fetchClientSecret: () => clientSecret,
appearance: {
variables: {
// This is the same color as tailwind color admin-portal-blue
colorPrimary: '#C8B56E', // optional appearance param,
},
},
});
so many lines for so much magic.
can't argue, it can be verbose for sure
Can you add a clean log in your fetchClientSecret callback thingy? I feel like you're hardcoding a value on load instead of explicitly calling your server to get a fresh one every time
fetchClientSecret: () => clientSecret, like this is supposed to call your server and get a fresh client_secret from a brand new AccountSession every time it's called
so if you can add a log line here where you log the client_secret value and see if this happens right before your error that would help
got it, so you want to see that client_secret value as it comes out from Stripe?
not really. It doesn't come from Stripe. It's your code. You are supposed to call your own server here and call the Create AccountSession API. This step https://docs.stripe.com/connect/embedded-onboarding?shell=true&api=true&client=react#create-an-account-session
I am currently guessing that you didn't understand that, created an AccountSession once when the app loaded and so now when Connect.js tries to get a fresh one, instead of going to your server to create a brand new one, you return the "cached" secret you had on load.
This is really just an educated guess, so adding a clear log to your callback there would help
I think I understand. I will see what I can find
Ok, so I got my endpoint to not cache data, thus seeing this behavior:
aka fresh account sessions / secrets each time
But still erroring
oh hold up
this error might be mine
2 seconds
yeah that error is different
yea I was looking at the wrong thing though, that error didn't block. it popped and then resolved.
this is the blocking error
same one I started with
this is coming back from that claim endpoint:
https://api.stripe.com/v1/account_sessions/claim
Hum and you are certain you are returning a unique AccountSession client_secret? sorry not seeing what you're seeing so I'm flying blind
Can you share that req_123 in text instead of a picture?
ooh sure sure
yea, the first image I have shared is the console.log() coming back from my server endpoint that is basically just hitting the https://api.stripe.com/v1/account_sessions and returning the clientSecret. The image shows several difrerent console.log()'s popping each with a unique clientSecret coming back on the different renders.
Then the second on is just the error:
You tried to claim an account session that has already been claimed.
I need the req_123456 in your picture
Are you talking about this text?
{
"code": "cannot_create_account_session",
"message": "You tried to claim an account session that has already been claimed.",
"request_log_url": "https://dashboard.stripe.com/test/logs/req_pKhb1FpiMQDfm1?t=1723762735",
"type": "invalid_request_error"
}
yes thanks
So you mentioned your earlier pictures were from your server-side code?
Are you certain you are properly returning the right updated client_secret in that callback client-side? Can you share your updated code for that part with exact logs so I can look at it?
sure! one second
const {
clientSecret,
isPending: isFetchClientSecretPending,
error: fetchClientSecretError,
} = useStipeFetchClientSecret(stripeAccountId);
if (isFetchClientSecretPending) return <LoadingState />;
if (fetchClientSecretError) {
return (
<ErrorState
error={fetchClientSecretError}
description="Please try again and contact support if this continues."
/>
);
}
console.log('[StripeConnectWrapper]', {
clientSecret,
});
const connectInstance = loadConnectAndInitialize({
publishableKey: stripeKey,
fetchClientSecret: () => clientSecret,
appearance: {
variables: {
// This is the same color as tailwind color admin-portal-blue
colorPrimary: '#C8B56E', // optional appearance param,
},
},
});
return (
<div className="text-center">
<ConnectComponentsProvider connectInstance={connectInstance}>
{children}
</ConnectComponentsProvider>
</div>
);
so you can see that I am logging right before the fresh secret is being provided to the loadConnectAndInitialize which is a Stripe function, not mine.
So to the best of my knowledge that function is eating a fresh secret each time.
hum
fetchClientSecret: () => clientSecret, this doesn't seem to fetch anything? This seems to still hardcode that id?
Can you add logs to that exact line of code to log the value you are returning to the component?
yup, let me give it a whirl with console.logs and see
thanks and please share the exact code you end up with. It's possible I'm wrong and your magic in React with useState and such dynamically changes the value, but it doesn't seem like it
Ok, so here is my console, both showing different Stripe errors as well as when my secrets were fresh...
oh and the only change I made was to console.log() inside of the fetchClientSecret :
fetchClientSecret: () => {
console.log('clientSecret inside of the fetchClientSecret', clientSecret);
return clientSecret;
},
Okay so you see a fresh id before you see the other error?
this looks like a clear duplicate no?
Like what I don't get is that your code is supposed to call your server during that callback
It really seems like my intuition is right and you return the same secret twice and the second time it errors
yea, that might be right. let me try and see what I can do with that
got it. thats helpful
I need to step out now unfortunately, but I will run with this and return if its still acting funny
thanks @undone whale ๐ป
Good luck!