Status: Public contract. Error codes and categories defined here are stable. Add new codes; never rename or renumber existing ones.
Historically, consumers had to parse human-readable error message strings to
understand failures. That is brittle: messages change, get localized, and can
leak secrets. This standard replaces that with:
- Stable error codes (
PocketPayError.code) — branch on these. - Categories (
PocketPayError.category) —WALLET,PAYMENT,TRANSACTION,NETWORK,SOROBAN,VAULT,SDK. - Safe messages (
PocketPayError.safeMessage) — user-facing, never secret. - Metadata (
ERROR_CODES) — retryability + HTTP status + developer hints. - Redaction helpers — strip secrets before logging.
import { PocketPayError, describeError, redactError, ErrorCategory } from 'stellar-pocketpay-sdk';
try {
await sendAsset(params);
} catch (err) {
if (err instanceof PocketPayError) {
// Branch on the stable code, not the message string.
switch (err.code) {
case 'NET_RATE_LIMITED':
await backOff(); // err.retryable === true
break;
case 'PAYMENT_SELF':
showUser(err.safeMessage); // safe, no secrets
break;
default:
// Always redact before logging.
console.error(redactError(err));
}
// Or use the structured descriptor:
const info = describeError(err.code);
console.log(info.category, info.retryable, info.safeMessage);
} else {
console.error(redactError(err));
}
}err.retryable === true(ordescribeError(code).retryable) means the operation is safe to retry (rate-limit, transient network, simulation).TX_STATUS_UNKNOWNmeans the outcome is unknown — poll status before deciding to rebuild or resubmit (it is not retryable as a blind resend).
| Category | Prefix | Examples |
|---|---|---|
| Wallet | WALLET_ |
WALLET_SECRET_EXPOSED, WALLET_ACCOUNT_UNFUNDED |
| Payment | PAYMENT_ |
PAYMENT_SELF, PAYMENT_TRUSTLINE_MISSING |
| Transaction | TX_ |
TX_EXPIRED, TX_FAILED, TX_STATUS_UNKNOWN |
| Network | NET_ |
NET_RATE_LIMITED, NET_TIMEOUT, NET_IDEMPOTENCY_CONFLICT |
| Soroban | SOROBAN_ |
SOROBAN_CONTRACT_ERROR, SOROBAN_RPC_UNAVAILABLE |
| Vault | VAULT_ |
VAULT_DEPOSIT_FAILED, VAULT_INSUFFICIENT_FUNDS |
| SDK | SDK_ |
SDK_CONFIG_INVALID, SDK_INTERNAL |
The full registry (with safeMessage, retryable, httpStatus,
developerHint) lives in src/errors/codes.ts (ERROR_CODES).
Never log raw error.message or error.cause — they may contain Stellar
secret keys (S...) or token material.
import { redactError, redactSensitive } from 'stellar-pocketpay-sdk';
console.error(redactError(err)); // structured, redacted
console.error(redactSensitive(rawString)); // scrub a stringclassifySubmitError already redacts secret material from raw submission
errors before attaching them to the returned PocketPayError.
- Before: you may have branched on codes like
PAYMENT_FAILED/SEND_ERROR. These are now mapped to the taxonomy (TX_FAILED,NET_RATE_LIMITED,TX_STATUS_UNKNOWN). Old codes still work as raw strings but are no longer the recommended contract. PocketPayErrorgained two optional fields —categoryandsafeMessage— with no change to the existing constructor signature, so existing call sites are unaffected.- Unknown codes fall back to
category: SDKand a generic safe message, so consumers can always rely ondescribeError()returning a usable object.
- Add the constant to
ErrorCodeinsrc/errors/codes.ts. - Add its
ErrorCodeSpectoERROR_CODES(category, retryable, safeMessage, developerHint). - Use the constant (not a string literal) wherever you throw.
- Add a test in
tests/error-standard.test.ts.