Error Handling
The Market Data PHP SDK uses a hierarchical exception system to handle different types of errors. Understanding these exceptions helps you build robust applications that gracefully handle failures.
Exception Hierarchy
MarketDataException (base)
├── ApiException - Business logic errors (invalid symbol, no data)
├── RequestError - Transient errors (5xx, timeouts) - triggers retry
└── BadStatusCodeError - Permanent errors (4xx) - no retry
└── UnauthorizedException - 401 authentication errors
Exception Types
MarketDataException
Base exception class for all SDK exceptions. All other exceptions extend this class.
<?php
use MarketDataApp\Client;
use MarketDataApp\Exceptions\MarketDataException;
try {
$client = new Client();
$quote = $client->stocks->quote('AAPL');
} catch (MarketDataException $e) {
// Catches all SDK exceptions
echo "SDK Error: " . $e->getMessage();
}
ApiException
Thrown for business logic errors returned by the API, such as invalid symbols or no data available.
<?php
use MarketDataApp\Client;
use MarketDataApp\Exceptions\ApiException;
try {
$client = new Client();
$quote = $client->stocks->quote('INVALID_SYMBOL_XYZ');
} catch (ApiException $e) {
echo "API Error: " . $e->getMessage() . "\n";
echo "HTTP Code: " . $e->getCode() . "\n";
// Get detailed support information
echo "Support Info:\n" . $e->getSupportInfo() . "\n";
// Get structured context for logging
$context = $e->getSupportContext();
print_r($context);
}
Common causes:
- Invalid or unknown symbol
- No data available for the requested date range
- Invalid parameter values
- Premium endpoint accessed without subscription
RequestError
Thrown for transient errors that may succeed on retry, such as server errors (5xx) or network timeouts.
<?php
use MarketDataApp\Client;
use MarketDataApp\Exceptions\RequestError;
try {
$client = new Client();
$quote = $client->stocks->quote('AAPL');
} catch (RequestError $e) {
echo "Transient Error: " . $e->getMessage() . "\n";
echo "This error may be resolved by retrying.\n";
}
Common causes:
- Server errors (500, 502, 503, 504)
- Network timeouts
- Connection failures
Note: The SDK automatically retries these errors with exponential backoff before throwing the exception.
BadStatusCodeError
Thrown for permanent HTTP errors (4xx) that will not succeed on retry.
<?php
use MarketDataApp\Client;
use MarketDataApp\Exceptions\BadStatusCodeError;
try {
$client = new Client();
$quote = $client->stocks->quote('AAPL');
} catch (BadStatusCodeError $e) {
echo "HTTP Error: " . $e->getCode() . "\n";
echo "Message: " . $e->getMessage() . "\n";
}
Common causes:
- 400 Bad Request (invalid parameters)
- 403 Forbidden (endpoint requires higher subscription tier)
- 404 Not Found (invalid endpoint)
- 429 Too Many Requests (rate limit exceeded)
UnauthorizedException
Thrown specifically for 401 authentication errors. Extends BadStatusCodeError.
<?php
use MarketDataApp\Client;
use MarketDataApp\Exceptions\UnauthorizedException;
try {
$client = new Client('invalid_token');
} catch (UnauthorizedException $e) {
echo "Authentication Failed: " . $e->getMessage() . "\n";
echo "Please check your API token.\n";
}
Common causes:
- Invalid API token
- Expired API token
- Missing API token
Support Information
All SDK exceptions provide methods for getting detailed error context:
getSupportInfo()
Returns a human-readable string with request details for support tickets:
<?php
use MarketDataApp\Exceptions\ApiException;
try {
// ... API call
} catch (ApiException $e) {
$supportInfo = $e->getSupportInfo();
// Returns formatted string like:
// Request URL: https://api.marketdata.app/v1/stocks/quotes/?symbol=INVALID
// HTTP Status: 400
// Error Message: Symbol not found
echo $supportInfo;
}
getSupportContext()
Returns an associative array with structured error context for logging:
<?php
use MarketDataApp\Exceptions\ApiException;
try {
// ... API call
} catch (ApiException $e) {
$context = $e->getSupportContext();
// Returns array like:
// [
// 'request_url' => 'https://api.marketdata.app/v1/stocks/quotes/?symbol=INVALID',
// 'http_status' => 400,
// 'error_message' => 'Symbol not found'
// ]
// Log to your monitoring system
$logger->error('API call failed', $context);
}
Handling Multiple Exception Types
Use a try-catch chain to handle different error types appropriately:
<?php
use MarketDataApp\Client;
use MarketDataApp\Exceptions\UnauthorizedException;
use MarketDataApp\Exceptions\ApiException;
use MarketDataApp\Exceptions\RequestError;
use MarketDataApp\Exceptions\BadStatusCodeError;
use MarketDataApp\Exceptions\MarketDataException;
try {
$client = new Client();
$quote = $client->stocks->quote('AAPL');
echo "Quote received: $" . $quote->last . "\n";
} catch (UnauthorizedException $e) {
// Handle authentication errors
echo "Authentication failed. Please check your API token.\n";
} catch (ApiException $e) {
// Handle business logic errors
echo "API Error: " . $e->getMessage() . "\n";
// Log details for troubleshooting
error_log("API Exception: " . $e->getSupportInfo());
} catch (RequestError $e) {
// Handle transient errors (already retried)
echo "Service temporarily unavailable. Please try again later.\n";
} catch (BadStatusCodeError $e) {
// Handle other HTTP errors
echo "Request failed with HTTP " . $e->getCode() . "\n";
} catch (MarketDataException $e) {
// Catch-all for any SDK exception
echo "Unexpected SDK error: " . $e->getMessage() . "\n";
}
Automatic Retry Behavior
The SDK automatically retries transient errors (RequestError) with exponential backoff:
- Initial delay: 1 second
- Maximum retries: 3 attempts
- Backoff multiplier: 2x per retry
- Jitter: Random variation to prevent thundering herd
If all retries fail, the exception is thrown to your code.
Best Practices
- Always catch exceptions - API calls can fail for various reasons
- Handle specific exceptions first - Catch more specific exceptions before general ones
- Log error context - Use
getSupportContext()for structured logging - Provide user feedback - Show appropriate messages for different error types
- Don't retry manually - The SDK handles retries for transient errors
Example: Robust API Call
<?php
use MarketDataApp\Client;
use MarketDataApp\Exceptions\UnauthorizedException;
use MarketDataApp\Exceptions\ApiException;
use MarketDataApp\Exceptions\MarketDataException;
function getStockQuote(string $symbol): ?object
{
static $client = null;
try {
if ($client === null) {
$client = new Client();
}
return $client->stocks->quote($symbol);
} catch (UnauthorizedException $e) {
// Critical error - cannot recover without new token
throw new RuntimeException('API authentication failed', 0, $e);
} catch (ApiException $e) {
// Symbol-specific error - log and return null
error_log("Failed to get quote for {$symbol}: " . $e->getMessage());
return null;
} catch (MarketDataException $e) {
// Other SDK errors - log and return null
error_log("SDK error for {$symbol}: " . $e->getMessage());
return null;
}
}
// Usage
$quote = getStockQuote('AAPL');
if ($quote) {
echo "AAPL: $" . $quote->last . "\n";
} else {
echo "Could not fetch quote for AAPL\n";
}