Handling errors

Many PayPal Here SDK calls perform asynchronous operations. These calls typically expect a parameter that contains a completion handle, which is an instance method or code block to be called when an asynchronous operation completes or fails. A completion handler expects one parameter that points to a PPHError object.

This example shows how a completion handler might be defined in a call to the PPHLocation class save method:

PPHLocation *loc = [locations objectAtIndex:0];
[loc save:^(PPHError *error) {
  self.locationWatcher = [
    [PayPalHereSDK sharedLocalManager]

    watcherForLocationId:loc.locationId withDelegate:self
  ];
  [self.locationWatcher update];
}];

If the operation completed, the completion manager's error parameter is nil. If the operation failed, it points to a PPHError object constructed by the SDK.

The following sections describe the properties of PPHError, which provide potentially useful information about the error.

For information about specific SDK call errors and recommended responses to them, see PayPal Here SDK reference documentation for PPHError and the comments in PPHError.h.

The domain property

The domain property indicates where an error originated (e.g. in one of the PayPal Here SDK's underlying services or in the app). The property can have one of several values:

  • PPHServer indicates an error that originated in one of the underlying services.
  • PPHLocal indicates an error that originated locally, that is, in the SDK itself or in the app.
  • PPHHTTP indicates an HTTP error, that is, a problem somewhere in the communication path between the app and one of the underlying services.
  • PPHInvoice indicates that the app failed to save an invoice, or an invoice operation was canceled.
  • Any other value indicates an iOS error. The SDK passes such errors through to the application.

The code property

The code property indicates the specific error that occurred. Its value is a number (an error code) which identifies the error.

For a local error, the code is defined in the SDK and you can check against it.

For example, consider the following subset of error codes (defined in PPHTransactionManager.h) which PPHTransactionManager can return:

\#define kPPHLocalErrorBadConfigurationNoCheckedInClient -2000
\#define kPPHLocalErrorBadConfigurationNoCardData -2001
\#define kPPHLocalErrorBadConfigurationNoManualCardData -2002
\#define kPPHLocalErrorBadConfigurationNoMerchant -2003
\#define kPPHLocalErrorBadConfigurationNoRecord -2004
\#define kPPHLocalErrorBadConfigurationInvalidState -2005
\#define kPPHLocalErrorBadConfigurationMerchantAccountNotActivatedForPayments -2006
\#define kPPHLocalErrorBadConfigurationInvalidParameters -2007
\#define kPPHLocalErrorBadConfigurationNoCurrentInvoice -2008
\#define kPPHLocalErrorBadConfigurationInvoiceAlreadyPaid -2009
\#define kPPHLocalErrorBadConfigurationNoInvoiceInTransactionRecord - 2011

These error codes often indicate a condition which the application could avoid by correct usage of the SDK.

The apiMessage property

For a service error, apiMessage often contains a description of the error addressed to the user. Such a message is generally suitable to be displayed in the UI.

Local errors, originating in the SDK, typically don't have an apiMessage value.

The devMessage property

The devMessage property often contains a description of the error addressed to the application developer. Such a description is generally not suitable to be displayed in the UI (i.e. to an end user). You can get access to a devMessage value by recording it in a log, or by processing either of these messages:

NSString *devMessage = [error.userInfo objectForKey:@"DevMessage"];
NSString *devMessage = error.devMessage;

How to process errors

Your error processing design should be guided by the questions:

  • What does this error mean to the user?
  • Can the app resolve it, or at least make it easier for the user to resolve?
  • What can the user do to resolve it?

Depending on the answers to these questions, it may be appropriate for the app to do one or more of these things:

  • Treat the error as an event that is exceptional but not 'wrong' (not really an error) and handle it automatically.
  • Report the error in terms that are meaningful to the user.
  • Offer the user a reasonable set of options for responding to the error.
  • Log the error, tell the user that something has gone wrong, and partially or completely abandon the operation that the app was trying to perform.
  • Do anything else that makes sense for the app and its intended user.

The more error conditions the app handles, and the more completely it handles them, the better the user experience it will provide.

A PPHServer error often represents a condition that is not an error from the app point of view. Such a condition should be handled by the app and it should not be logged or displayed to the user as the PPHServer object describes it.

For example, an 'error' that indicates card declined or charge exceeds merchant limits should make the app report the condition to the user and offer appropriate response options.

A PPHLocal error or iOS error (with a none of the above value in domain) is usually caused by improper use or configuration of the SDK. Make the app log the error's details. When you review the log, think about whether you can change the app to prevent the error from occurring.

A PPHHTTP error may mean that the app does not have access to the Internet (prompt the user to enable WiFi or 3G), that one of the underlying services isn't available (ask the user to be patient), or that the service has denied access to the app (try again later; contact PayPal user support if it still doesn't work).

PPHInvoice errors fall into two categories. An error that follows a 'cancel invoice' operation is not really an error it's just a confirmation that the invoice was canceled successfully. An error that follows an attempt to make a payment or save an invoice is similar in nature to a PPHLocal error, and should be handled similarly.