{
  "id": "error-handling",
  "title": "Error handling",
  "url": "https://redis.io/docs/latest/develop/clients/php/error-handling/",
  "summary": "Learn how to handle errors when using Predis.",
  "tags": [],
  "last_updated": "2026-07-24T10:52:10-07:00",
  "page_type": "content",
  "content_hash": "dc37788296c2aef7e9edef501640eab3aa102605e23104957303cac746b7ff76",
  "sections": [
    {
      "id": "overview",
      "title": "Overview",
      "role": "overview",
      "text": "Predis uses **exceptions** to signal errors. Documentation examples often omit\nerror handling for brevity, but production code should distinguish between\ntransient transport errors and server-side command errors. This page explains\nhow Predis error handling works and how to apply common error handling\npatterns.\n\nFor an overview of error types and handling strategies, see\n[Error handling](https://redis.io/docs/latest/develop/clients/error-handling)."
    },
    {
      "id": "exception-hierarchy",
      "title": "Exception hierarchy",
      "role": "errors",
      "text": "Predis groups its exceptions under `PredisException`:\n\n[code example]"
    },
    {
      "id": "key-exceptions",
      "title": "Key exceptions",
      "role": "content",
      "text": "The following exceptions are the most commonly encountered in Predis\napplications. See\n[Categories of errors](https://redis.io/docs/latest/develop/clients/error-handling#categories-of-errors)\nfor a more detailed discussion of these errors and their causes.\n\n| Exception | When it occurs | Recoverable | Recommended action |\n|---|---|---|---|\n| `Predis\\Connection\\ConnectionException` | Predis could not connect or lost the connection | ✅ | Retry with backoff or fall back |\n| `Predis\\CommunicationException` | A transport-level error occurred while reading or writing | ✅ | Retry with backoff and reconnect |\n| `Predis\\Response\\ServerException` | Redis returned an error reply such as `WRONGTYPE` | ❌ | Fix the command, arguments, or data model |\n| `Predis\\Transaction\\AbortedMultiExecException` | A watched transaction was aborted | ✅ | Reload state and retry the transaction |"
    },
    {
      "id": "applying-error-handling-patterns",
      "title": "Applying error handling patterns",
      "role": "content",
      "text": "The [Error handling](https://redis.io/docs/latest/develop/clients/error-handling) overview\ndescribes four main patterns. The sections below show how to implement them in\nPredis:"
    },
    {
      "id": "pattern-1-fail-fast",
      "title": "Pattern 1: Fail fast",
      "role": "content",
      "text": "Catch specific exceptions that represent unrecoverable errors and re-throw them\n(see\n[Pattern 1: Fail fast](https://redis.io/docs/latest/develop/clients/error-handling#pattern-1-fail-fast)\nfor a full description):\n\n[code example]"
    },
    {
      "id": "pattern-2-graceful-degradation",
      "title": "Pattern 2: Graceful degradation",
      "role": "content",
      "text": "Catch connection problems and fall back to an alternative (see\n[Pattern 2: Graceful degradation](https://redis.io/docs/latest/develop/clients/error-handling#pattern-2-graceful-degradation)\nfor a full description):\n\n[code example]"
    },
    {
      "id": "pattern-3-retry-with-backoff",
      "title": "Pattern 3: Retry with backoff",
      "role": "content",
      "text": "Retry on temporary communication failures (see\n[Pattern 3: Retry with backoff](https://redis.io/docs/latest/develop/clients/error-handling#pattern-3-retry-with-backoff)\nfor a full description):\n\n[code example]"
    },
    {
      "id": "pattern-4-log-and-continue",
      "title": "Pattern 4: Log and continue",
      "role": "content",
      "text": "Log non-critical failures and continue (see\n[Pattern 4: Log and continue](https://redis.io/docs/latest/develop/clients/error-handling#pattern-4-log-and-continue)\nfor a full description):\n\n[code example]"
    },
    {
      "id": "transaction-retries",
      "title": "Transaction retries",
      "role": "content",
      "text": "Predis raises `AbortedMultiExecException` when an optimistic-locking\ntransaction aborts. Handle this the same way as other retryable conflicts:\n\n[code example]"
    },
    {
      "id": "see-also",
      "title": "See also",
      "role": "related",
      "text": "- [Error handling](https://redis.io/docs/latest/develop/clients/error-handling)\n- [Pipelines and transactions](https://redis.io/docs/latest/develop/clients/php/transpipe)"
    }
  ],
  "examples": [
    {
      "id": "exception-hierarchy-ex0",
      "language": "hierarchy {type=\"exception\"}",
      "code": "\"PredisException\":\n    _meta:\n        description: \"Base class for Predis exceptions\"\n    \"CommunicationException\":\n        \"ConnectionException\":\n        \"ProtocolException\":\n    \"ClientException\":\n    \"ServerException\":\n    \"AbortedMultiExecException\":\n    \"...\":\n        _meta:\n            ellipsis: true\n            description: \"Other Predis exception types\"",
      "section_id": "exception-hierarchy"
    },
    {
      "id": "pattern-1-fail-fast-ex0",
      "language": "php",
      "code": "use Predis\\Response\\ServerException;\n\ntry {\n    return $r->get($key);\n} catch (ServerException $e) {\n    // This indicates a bug in our code or schema.\n    throw $e;\n}",
      "section_id": "pattern-1-fail-fast"
    },
    {
      "id": "pattern-2-graceful-degradation-ex0",
      "language": "php",
      "code": "use Predis\\Connection\\ConnectionException;\n\ntry {\n    $cachedValue = $r->get($key);\n    if ($cachedValue !== null) {\n        return $cachedValue;\n    }\n} catch (ConnectionException $e) {\n    $logger->warning('Cache unavailable, using database');\n}\n\nreturn $database->get($key);",
      "section_id": "pattern-2-graceful-degradation"
    },
    {
      "id": "pattern-3-retry-with-backoff-ex0",
      "language": "php",
      "code": "use Predis\\CommunicationException;\n\n$delayMs = 100;\n\nfor ($attempt = 0; $attempt < 3; $attempt++) {\n    try {\n        return $r->get($key);\n    } catch (CommunicationException $e) {\n        if ($attempt === 2) {\n            throw $e;\n        }\n\n        usleep($delayMs * 1000);\n        $delayMs *= 2;\n    }\n}",
      "section_id": "pattern-3-retry-with-backoff"
    },
    {
      "id": "pattern-4-log-and-continue-ex0",
      "language": "php",
      "code": "use Predis\\CommunicationException;\n\ntry {\n    $r->setex($key, 3600, $value);\n} catch (CommunicationException $e) {\n    $logger->warning(\"Failed to cache {$key}, continuing without cache\");\n}",
      "section_id": "pattern-4-log-and-continue"
    },
    {
      "id": "transaction-retries-ex0",
      "language": "php",
      "code": "use Predis\\Transaction\\AbortedMultiExecException;\n\nfor ($attempt = 0; $attempt < 3; $attempt++) {\n    try {\n        return $r->transaction(['cas' => true, 'watch' => $key], function ($tx) use ($key) {\n            $current = $tx->get($key);\n            $tx->multi();\n            $tx->set($key, strtoupper($current));\n        });\n    } catch (AbortedMultiExecException $e) {\n        if ($attempt === 2) {\n            throw $e;\n        }\n    }\n}",
      "section_id": "transaction-retries"
    }
  ]
}
