#demodian_best-practices

1 messages ยท Page 1 of 1 (latest)

native palmBOT
#

๐Ÿ‘‹ 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/1392188770228506654

๐Ÿ“ Have more to share? Add more details, code, screenshots, videos, etc. below.

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.

golden lagoon
#

Hi hi! Can you tell me what version of the SDK you're using?

blissful mason
#

15.7.0

native palmBOT
blissful mason
#

I haven't had an opportunity to update to latest and greatest yet

#

probably should, but i've got other major fires on my plate

golden lagoon
#

No no, no worries. You shouldn't have to until you're ready (other than security-related things).

blissful mason
#

i've seen that, but the SDK has like 21 different exceptions defined (that I've found so far). unless I go through the SDK source and check every class/method, how will I easily know which exceptions to guard against?

#

the structure of the SDK is layered, so how do I know which exceptions to use without a lot of digging?

lapis wharf
#

hi! fyi i'm taking over this thread - catching up on a few things but i'll get back to you asap

#

ok, my attention is back here... i think the guide timebox listed is the best source we have on error handling but i can poke around a bit more

blissful mason
#

short of checking Google AI to look at different code examples, is there a best-case reference for all exceptions to use and when for the different methods other than the SDK itself?

#

i'm trying to tidy up the code. had to update our production site to match our testing site. the production site was at SDK version 7.x.x so at least it's now ad 15.x.x, but I just want to make sure I at least get the basics updated. I would still have to check everything versus 17.x.x which is latest

native palmBOT
blissful mason
#

for the most part, the major one used is ApiErrorException, but with 20 other exceptions, when are they used? i just want to make sure this wrapper is bulletproof

lapis wharf
#

i'm a little less familiar with the PHP SDK, so the exceptions documented in the error handling page are the ones i'm more familiar with. i might need to run this by someone with a little more experience with the PHP SDK specifically, but in the meantime can you share an example exception you've run into that isn't documented on that page?

blissful mason
#

as far as I'm aware, this is the full list I've found just looking in the lib/Exception directory:

use Stripe\Exception\ApiConnectionException;
use Stripe\Exception\ApiErrorException;
use Stripe\Exception\AuthenticationException;
use Stripe\Exception\BadMethodCallException;
use Stripe\Exception\CardException;
use Stripe\Exception\IdempotencyException;
use Stripe\Exception\InvalidArgumentException;
use Stripe\Exception\InvalidRequestException;
use Stripe\Exception\OAuth\InvalidClientException.php
use Stripe\Exception\OAuth\InvalidGrantException.php
use Stripe\Exception\OAuth\InvalidRequestException.php
use Stripe\Exception\OAuth\InvalidScopeException.php
use Stripe\Exception\OAuth\OAuthErrorException.php
use Stripe\Exception\OAuth\UnknownOAuthErrorException.php
use Stripe\Exception\OAuth\UnsupportedGrantTypeException.php
use Stripe\Exception\OAuth\UnsupportedResponseTypeException.php
use Stripe\Exception\PermissionException;
use Stripe\Exception\RateLimitException;
use Stripe\Exception\SignatureVerificationException;
use Stripe\Exception\UnexpectedValueException;
use Stripe\Exception\UnknownApiErrorException;

#

just wanting to know if these are all required and how I need to protect against them

lapis wharf
#

still digging on this... gimme a bit

blissful mason
#

no problem. So far looking in the SDK for all class/methods we use, everything looks like ApiErrorException (except for the case of OAuthErrorException) in the source, but if that's all that's being used, then why are all the others there?

lapis wharf
#

yeah that's what i'm trying to figure out too haha

blissful mason
#

for example searching the SDK for CardException, i get this:

init.php:require DIR . '/lib/Exception/CardException.php';
lib/ApiRequestor.php: return Exception\CardException::factory($msg, $rcode, $rbody, $resp, $rheaders, $code, $declineCode, $param);
lib/Charge.php: * These strings are applicable to the decline_code property of the \Stripe\Exception\CardException exception.
lib/Exception/CardException.php: * CardException is thrown when a user enters a card that can't be charged for
lib/Exception/CardException.php:class CardException extends ApiErrorException
lib/Exception/CardException.php: * Creates a new CardException exception.
lib/Exception/CardException.php: * @return CardException

looks like the only use is Charge API Requestors?

#

but that's not for any method, but rather a block of consts for the class

#

tells me that the code documentation is possibly lacking for all possible exceptions on methods, since i know that payment intents can be for card transactions, yet there's no reference to CardException in PaymentIntent.php

#

make sense?

#

I hope I'm not starting too much a problem with this issue...

lapis wharf
#

haha no, you're fine! i'm juggling a few things at the moment, sorry for being slow

blissful mason
#

no worries. I'm working on other code changes while I wait

native palmBOT
coral fable
#

Hello
The exceptions you need to guard against are typically dependent on what sort of integration you're building and what APIs you're using
The ones outlined in the doc here are the recommended ones that apply to most integrations - https://docs.stripe.com/error-handling?lang=php#error-types

However, if you're particularly worried about a specific usecase - you can test your code using various test cards
https://docs.stripe.com/testing and see what sort of exceptions are thrown

blissful mason
#

that seems like a bit of a weak response considering the SDK source should be the bible, and I shouldn't have to run through every situation because I don't know what cases apply in every situation. If an exception is possible, it should be listed, right?

#

I really don't have time to figure out the whole SDK with all kinds of random testing and see where things blow up. It should be documented

#

and I have absolutely no control over what the Stripe servers will return as issues

coral fable
#

I get that but you do know what API endpoints you're planning to use/using right? If so, you can guard against the relevant ones listed in the docs?

For example, are you integrating a webhook? If so, you would likely run into Stripe\Exception\SignatureVerificationException. Are you using any OAuth based flows? If so, you may need to guard against OAuth specific exceptions.

blissful mason
#

I went through the SDK source checking all class/methods I use, and there are only two listed through the SDK, and that's ApiErrorException and OAuthErrorException.

coral fable
#

Listed where?

blissful mason
#

example, in lib/PaymentIntent.php line 112 for the create() method

#

line 238 for capture() method

#

capture() is when you try to capture the charge for the payment intent, right? there could be issues with a card, if it's a card purchase

#

/**
* @param null|array $params
* @param null|array|string $opts
*
* @return PaymentIntent the captured payment intent
*
* @throws Exception\ApiErrorException if the request fails
*/
public function capture($params = null, $opts = null)
{
$url = $this->instanceUrl() . '/capture';
list($response, $opts) = $this->_request('post', $url, $params, $opts);
$this->refreshFrom($response, $opts);

    return $this;
}
coral fable
#

Are you setting capture_method: 'manual' when you create a PaymentIntent?

blissful mason
#

yeah, especially with the terminal

coral fable
#

If the capture request fails, it will throw ApiErrorException with the appropriate error message

#

I don't believe it raises a CardException

blissful mason
#

ever?

#

if ApiErrorException is a catch-all case, then why do the others exist?

coral fable
#

I wouldn't say ever.. but it depends on what caused the request to fail.

blissful mason
#

in lib/ApiRequestor.php line 218, there's a switch with a lot based on response code, I'm guessing, but that looks like status codes from the server. so when would they be applicable?

#

I remember back in older versions of the SDK, examples would have lots of catch() blocks, and if I didn't have them all, there'd be something that would die in the code. But having huge lists of unnecessary chains of catches is ugly if they are not ever emitted./triggered

#

(and just a heads up, I've got about 20 minutes left before I have to shutdown my computer)

coral fable
#

The code in ApiRequestor is lower level afaik. That is something abstracted behind SDK methods.

Pardon my naive understanding of PHP but you could do something like

  catch (Throwable $e){
      call_some_generic_function_to_handle($e);
  }

and catch all exceptions right? Inside there, you could check for these types: https://docs.stripe.com/error-handling?lang=php#error-types and if it's not one of these, maybe set off an alert?

blissful mason
#

<?php
require 'vendor/autoload.php';
\Stripe\Stripe::setApiKey('sk_test_BQokikJOvBiI2HlWgH4olfQ2');

function example_function($args) {
try {
$stripe->paymentIntents->create($args);
error_log("No error.");
} catch(\Stripe\Exception\CardException $e) {
error_log("A payment error occurred: {$e->getError()->message}. (request id: {$e->getRequestId()})");
} catch (\Stripe\Exception\InvalidRequestException $e) {
error_log("An invalid request occurred. (request id: {$e->getRequestId()})");
} catch (Exception $e) {
error_log("Another problem occurred, maybe unrelated to Stripe.");
}
}

this is the example code in the page for php error handling, yet ApiErrorException is not used. would it failover to Exception or does it have to be specifically listed?

coral fable
#

It would be caught by the Exception line, yes

blissful mason
#

because my diff of an affected code is this:

            try {
                    Account::retrieve($token, []);
                    return Payment::SUCCESS;
  •           } catch(Exception $e) {
    
  •           } catch(ApiErrorException $e) {
                      Payment::set_error("Account connection revoked - check failed for {$eventid}");
                      return Payment::ERROR;
              }
    

and it failed to capture the general exception

#

that was the error I dealt with this morning

#

yes, I had a bad value for token, but the catch(Exception $e) did not catch the error

coral fable
#

It should've as far as I know unless it was caught earlier in the chain

blissful mason
#

there was nothing else in the chain as I could tell. that was the perplexing part. the original code was just the Exception. the code now reads ApiErrorException.

#

[08-Jul-2025 11:19:30 America/Chicago] PHP Fatal error: Uncaught Error sending request to Stripe: (Status 403) The provided key 'sk_test_***********************************************************************************************Dy0s' does not have access to account 'Stripe' (or that account does not exist). Application access may have been revoked.
Stripe\Exception\PermissionException: The provided key 'sk_test_***********************************************************************************************Dy0s' does not have access to account 'Stripe' (or that account does not exist). Application access may have been revoked. in /mtp/inc/payments/stripe-php-master/lib/Exception/ApiErrorException.php:38
Stack trace:
#0 /mtp/inc/payments/stripe-php-master/lib/ApiRequestor.php(234): Stripe\Exception\ApiErrorException::factory()
#1 /mtp/inc/payments/stripe-php-master/lib/ApiRequestor.php(187): Stripe\ApiRequestor::_specificAPIError()
#2 /mtp/inc/payments/stripe-php-master/lib/ApiRequestor.php(577): Stripe\ApiRequestor->handleErrorResponse()
#3 /mtp/inc/payments/str in /mtp/inc/payments/stripe-php-master/lib/Exception/ApiErrorException.php on line 38

#

that was my error log this mornign

#

the account 'Stripe' was my fault, but the general exception was NOT caught

coral fable
#

What version of PHP are you running?

blissful mason
#

it's 7.4 on this server

#

it's 20.04 Ubuntu, and that will need to be updated, but we'd need another machine to get to a newer OS version and php

coral fable
#

You could try with catch (Throwable $e) and re-test with the same API request

#

I believe Throwable is supported in PHP 7+

native palmBOT
blissful mason
#

it is, but that's a very last ditch thing to look for.. and i'm going to have to shutdown

#

On my phone for now

safe sphinx
#

What does 'and i'm going to have to shutdown' mean?

blissful mason
#

My laptop. Changing my location

#

(At dialysis, and my session is finishing)

safe sphinx
#

I see, please take care of yourself. We will be here

blissful mason
#

The example on the error handling page just lists Exception, which was available in 7.4, but it failed as a fallback

safe sphinx
#

There are a ton of back and forth here. Can you summary the latest question for me please?

blissful mason
#

Shouldn't the SDK source document all of the possible exceptions for each method? Everything is basically just ApiErrorException for what I use in the method documentation in the source

#

(Typing will be tough for the next few minutes)

safe sphinx
#

I can share your feedback to document all the possible exceptions for each method to the owning team for product reiterations.

blissful mason
#

Some but not exhaustive. A general purpose Exception fail to catch it

#

Not sure if that's a problem with php 7.4, but it's my situation this morning

safe sphinx
#

To ensure we're on the same page, are you saying that the general purpose Exception did not capture ApiErrorException?

blissful mason
#

Yes

safe sphinx
blissful mason
#

Sure

native palmBOT
summer iron
#

๐Ÿ‘‹ do you have a clear basic end-to-end PHP script that reproduces the error?

blissful mason
#

back on laptop. I can get one put together in a few minutes

summer iron
#

Thanks I think it will help align versus a meta discussion about what might happen

blissful mason
summer iron
#

Here's my basic repro script:


error_reporting(E_ALL);
ini_set('display_errors', 1);

require_once('vendor/autoload.php');

$stripe = new \Stripe\StripeClient([
  'api_key' => 'sk_test_BQokikJOvBiI2HlWgH4olfQ2',
]);

try {
  echo "Trying to create a Payout<br>";
  $payout = $stripe->payouts->create([
      'amount' => 100,
      'currency' => 'eur',
  ]);
  echo "succeeded!<br>";
} catch(\Stripe\Exception\CardException $e) {
  error_log("A CardException occurred");
  echo "A CardException occurred: " .$e->getError()->message . " - Request id: " . $e->getRequestId();
} catch (\Stripe\Exception\InvalidRequestException $e) {
  error_log("An InvalidRequestException occurred");
  echo "An InvalidRequestException occurred: " .$e->getError()->message . " - Request id: " . $e->getRequestId();
} catch (\Stripe\Exception\ApiErrorException $e) {
  error_log("A generic Stripe ApiErrorException occurred");
  echo "A generic Stripe Exception occurred: " .$e->getError()->message . " - Request id: " . $e->getRequestId();
}catch (Exception $e) {
  echo "an error occurred that isn't Stripe";
}```

This will fail in the second catch with `InvalidRequestException` because it's a 400. If you remove that one it then ends up in the next one. And if you remove that one it ends up in Exception
blissful mason
#

sorry, yeah, needs the other things at the top

summer iron
#

Can you try mine first and confirm the behaviour? Yours is a bit less straightforward with your import and not using the \Stripe paths

blissful mason
#

it's working with the example (but all specific exceptions commented out) I even made it similar to my style (e.g. Account::retrieve()) and the example is okay. this is weird

golden lagoon
#

Hi again! In that case, the issue must be happening elsewhere in your code.

blissful mason
#

i'm checking for Exception to see if it is defined somewhere else, but the error message was specifically Stripe-related

#

i can run the old code on our beta site and it is still doing it because it hasn't been updated yet

summer iron
#

I wonder if it is to do with your use Stripe\Account; use Stripe\Stripe;

#

I'm a PHP developer in theory but I learnt all of my craft before namespaces were introduced ๐Ÿ˜‚
I feel like this is kinda catching the "wrong" exception. Maybe try catch (\Exception $e)?

blissful mason
#

that's valid PHP though... moment

#

damn, that did it. okay, i feel like an idiot -_-

#

thank you

#

(though to be exact, knowing when to handle specific exceptions would be important, so updated documentation would be helpful depending on the actions that have to be taken)

summer iron
#

In most cases you'd handle all Stripe exceptions the same other than the card decline one which I would special-case

blissful mason
#

the code that was failing for this was in a namespace, so maybe have it listed as \Exception in the example?

#

just to be explicit, because i'm sure no one actually puts all their Stripe code in a public web root

summer iron
#

I mean web root and namespacing are unrelated

#

the example already uses \Stripe\ which makes it explicit in which case Exception is correct. It's when you change the namespacing that it doesn't work.

#

I'll flag but I'm dubious we'd write \Exception just to catch that use-case though you aren't the first one hitting this (which is why I offered that alternative from some previous convos) so maybe it'd still help

blissful mason
#

please

golden lagoon
blissful mason
#

(this is a custom framework, and i didn't have a use \Exception; so yeah... -_-)

summer iron
#

@golden lagoon sure that part we were aligned on

blissful mason
#

anyhow, thank you all for your patience

summer iron
#

sure thing!