Error handling
Learn how to handle errors when using Predis.
Predis uses exceptions to signal errors. Documentation examples often omit error handling for brevity, but production code should distinguish between transient transport errors and server-side command errors. This page explains how Predis error handling works and how to apply common error handling patterns.
For an overview of error types and handling strategies, see Error handling.
Exception hierarchy
Predis groups its exceptions under PredisException:
"PredisException":
_meta:
description: "Base class for Predis exceptions"
"CommunicationException":
"ConnectionException":
"ProtocolException":
"ClientException":
"ServerException":
"AbortedMultiExecException":
"...":
_meta:
ellipsis: true
description: "Other Predis exception types"
Key exceptions
The following exceptions are the most commonly encountered in Predis applications. See Categories of errors for a more detailed discussion of these errors and their causes.
| Exception | When it occurs | Recoverable | Recommended action |
|---|---|---|---|
Predis\Connection\ConnectionException |
Predis could not connect or lost the connection | ✅ | Retry with backoff or fall back |
Predis\CommunicationException |
A transport-level error occurred while reading or writing | ✅ | Retry with backoff and reconnect |
Predis\Response\ServerException |
Redis returned an error reply such as WRONGTYPE |
❌ | Fix the command, arguments, or data model |
Predis\Transaction\AbortedMultiExecException |
A watched transaction was aborted | ✅ | Reload state and retry the transaction |
Applying error handling patterns
The Error handling overview describes four main patterns. The sections below show how to implement them in Predis:
Pattern 1: Fail fast
Catch specific exceptions that represent unrecoverable errors and re-throw them (see Pattern 1: Fail fast for a full description):
use Predis\Response\ServerException;
try {
return $r->get($key);
} catch (ServerException $e) {
// This indicates a bug in our code or schema.
throw $e;
}
Pattern 2: Graceful degradation
Catch connection problems and fall back to an alternative (see Pattern 2: Graceful degradation for a full description):
use Predis\Connection\ConnectionException;
try {
$cachedValue = $r->get($key);
if ($cachedValue !== null) {
return $cachedValue;
}
} catch (ConnectionException $e) {
$logger->warning('Cache unavailable, using database');
}
return $database->get($key);
Pattern 3: Retry with backoff
Retry on temporary communication failures (see Pattern 3: Retry with backoff for a full description):
use Predis\CommunicationException;
$delayMs = 100;
for ($attempt = 0; $attempt < 3; $attempt++) {
try {
return $r->get($key);
} catch (CommunicationException $e) {
if ($attempt === 2) {
throw $e;
}
usleep($delayMs * 1000);
$delayMs *= 2;
}
}
Pattern 4: Log and continue
Log non-critical failures and continue (see Pattern 4: Log and continue for a full description):
use Predis\CommunicationException;
try {
$r->setex($key, 3600, $value);
} catch (CommunicationException $e) {
$logger->warning("Failed to cache {$key}, continuing without cache");
}
Transaction retries
Predis raises AbortedMultiExecException when an optimistic-locking
transaction aborts. Handle this the same way as other retryable conflicts:
use Predis\Transaction\AbortedMultiExecException;
for ($attempt = 0; $attempt < 3; $attempt++) {
try {
return $r->transaction(['cas' => true, 'watch' => $key], function ($tx) use ($key) {
$current = $tx->get($key);
$tx->multi();
$tx->set($key, strtoupper($current));
});
} catch (AbortedMultiExecException $e) {
if ($attempt === 2) {
throw $e;
}
}
}