From 33f6d618a4521755d4ea035a06b3110e8021adcf Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Fri, 31 Oct 2025 15:10:11 +0000 Subject: [PATCH 01/16] DOC-5881 enable Mermaid diagrams --- assets/css/index.css | 6 ++++++ .../_markup/render-codeblock-mermaid.html | 7 +++++++ layouts/_default/baseof.html | 15 +++++++++++++++ 3 files changed, 28 insertions(+) create mode 100644 layouts/_default/_markup/render-codeblock-mermaid.html diff --git a/assets/css/index.css b/assets/css/index.css index 111532dd19..7978ee7063 100644 --- a/assets/css/index.css +++ b/assets/css/index.css @@ -88,6 +88,12 @@ section.prose { @apply bg-slate-900 rounded-lg; } +.prose pre.mermaid { + background-color: white !important; + border-radius: 0.5rem; + padding: 1rem; +} + .prose pre > code { @apply bg-none font-monogeist; } diff --git a/layouts/_default/_markup/render-codeblock-mermaid.html b/layouts/_default/_markup/render-codeblock-mermaid.html new file mode 100644 index 0000000000..9915805e2b --- /dev/null +++ b/layouts/_default/_markup/render-codeblock-mermaid.html @@ -0,0 +1,7 @@ +{{ $width := (index .Attributes "width") | default "75%" }} +
+
+    {{ .Inner | htmlEscape | safeHTML }}
+
+
+{{ .Page.Store.Set "hasMermaid" true }} diff --git a/layouts/_default/baseof.html b/layouts/_default/baseof.html index a15d1e0625..da998cde52 100644 --- a/layouts/_default/baseof.html +++ b/layouts/_default/baseof.html @@ -79,5 +79,20 @@ {{ partial "toc-js.html" . }} {{ partial "search-modal.html" . }} + + {{ if .Store.Get "hasMermaid" }} + + {{ end }} From 89cfafd72b3285fd6450b8bb0b2f74644aa48782 Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Fri, 31 Oct 2025 15:11:09 +0000 Subject: [PATCH 02/16] DOC-5881 first draft of error handling page --- content/develop/clients/error-handling.md | 357 ++++++++++++++++++++++ 1 file changed, 357 insertions(+) create mode 100644 content/develop/clients/error-handling.md diff --git a/content/develop/clients/error-handling.md b/content/develop/clients/error-handling.md new file mode 100644 index 0000000000..33617eca52 --- /dev/null +++ b/content/develop/clients/error-handling.md @@ -0,0 +1,357 @@ +--- +title: Error handling +description: Learn how to handle errors when using Redis client libraries +linkTitle: Error handling +weight: 50 +--- + +When working with Redis, errors can occur for various reasons—network issues, invalid commands, or resource constraints. This guide explains the types of errors you might encounter and how to handle them effectively. + +## Categories of errors + +### Connection errors + +Connection errors occur when your application cannot communicate with Redis. These are typically temporary and often recoverable. + +**Common causes:** +- Network connectivity issues +- Redis server is down or unreachable +- Authentication failure +- Connection timeout +- Connection pool exhaustion + +**Examples:** +- `ConnectionError`: Network failure or server unreachable +- `TimeoutError`: Operation exceeded the configured timeout +- `AuthenticationError`: Invalid credentials + +**When to handle:** Almost always. Connection errors are usually temporary, so implementing retry logic or fallback strategies is recommended. + +**Example strategy:** + +```mermaid {width="100%"} +graph TB + A["Try to connect
to Redis"] + A -->|Success| B(["Use the result"]) + A -->|Failure| C{Error type?} + C -->|Timeout| D(["Retry with
exponential backoff"]) + C -->|Auth failure| E(["Check credentials
and fail"]) + C -->|Network error| F(["Fallback to
alternative data source"]) +``` + +### Command errors + +Command errors occur when Redis receives an invalid or malformed command. These typically indicate a bug in your code. + +**Common causes:** +- Typo in command name +- Wrong number of arguments +- Invalid argument types +- Using a command that doesn't exist in your Redis version + +**Examples:** +- `ResponseError`: Invalid command or syntax error +- `WRONGTYPE Operation against a key holding the wrong kind of value` +- `ERR unknown command` + +**When to handle:** Rarely. These usually indicate a programming error and should be fixed in your code, not handled at runtime. However, some cases (like invalid user input) may warrant handling. + +**Example:** + +```mermaid {width="60%"} +graph TB + A["User provides
JSONPath expression"] + A --> B["Try to execute it"] + direction TB + B -->|ResponseError| C["Log the error"] + C --> D(["Return default value
or error message to user"]) + B -->|Success| E(["Use the result"]) +``` + +### Data errors + +Data errors occur when there's a problem with the data itself—serialization failures, corrupted data, or type mismatches. + +**Common causes:** +- Object cannot be serialized to JSON +- Cached data is corrupted +- Attempting to deserialize invalid data +- Type mismatch (e.g., trying to use string operations on a list) + +**Examples:** +- `JSONDecodeError`: Cannot deserialize JSON data +- `SerializationError`: Cannot serialize object +- `WRONGTYPE`: Operating on wrong data type + +**When to handle:** Sometimes. If the error is due to user input or external data, handle it gracefully. If it's due to your code, fix the code. + +**Example:** + +```mermaid {width="60%"} +graph TB + A["Read cached data"] + A --> B["Try to deserialize"] + B -->|Success| C(["Use the data"]) + B -->|Deserialization fails| D["Log the error"] + D --> E["Delete corrupted
cache entry"] + E --> F(["Fetch fresh data
from source"]) +``` + +### Resource errors + +Resource errors occur when Redis runs out of resources or hits limits. + +**Common causes:** +- Memory limit reached +- Connection pool exhausted +- Too many connections +- Key eviction due to memory pressure + +**Examples:** +- `OOM command not allowed when used memory > 'maxmemory'` +- Connection pool timeout +- `LOADING Redis is loading the dataset in memory` + +**When to handle:** Sometimes. Some resource errors are temporary (Redis loading), while others indicate a configuration problem. + +**Example:** + +```mermaid {width="80%"} +graph TB + A{Resource error
occurred?} + A -->|Redis loading| B(["Retry after
a delay"]) + A -->|Memory full| C(["Check Redis
configuration and data"]) + A -->|Pool exhausted| D(["Increase pool size
or reduce concurrency"]) +``` + +## Error handling patterns + +### Pattern 1: Fail fast + +Use this when the error is unrecoverable or indicates a bug in your code. + +**When to use:** +- Command errors (invalid syntax) +- Authentication errors +- Programming errors + +**Example:** +```python +try: + result = r.get(key) +except redis.ResponseError as e: + # This indicates a bug in our code + raise # Re-raise the exception +``` + +### Pattern 2: Graceful degradation + +Use this when you have an alternative way to get the data. + +**When to use:** +- Cache reads (fallback to database) +- Session reads (fallback to default values) +- Optional data (skip if unavailable) + +**Example:** +```python +try: + cached_value = r.get(key) + if cached_value: + return cached_value +except redis.ConnectionError: + logger.warning("Cache unavailable, using database") + +# Fallback to database +return database.get(key) +``` + +### Pattern 3: Retry with backoff + +Use this when the error is temporary and the operation is idempotent. + +**When to use:** +- Connection timeouts +- Temporary network issues +- Redis loading data + +**Example:** +```python +import time + +max_retries = 3 +retry_delay = 0.1 + +for attempt in range(max_retries): + try: + return r.get(key) + except redis.TimeoutError: + if attempt < max_retries - 1: + time.sleep(retry_delay) + retry_delay *= 2 # Exponential backoff + else: + raise +``` + +### Pattern 4: Log and continue + +Use this when the operation is not critical to your application. + +**When to use:** +- Cache writes (data loss is acceptable) +- Non-critical updates +- Metrics collection + +**Example:** +```python +try: + r.setex(key, 3600, value) +except redis.ConnectionError: + logger.warning(f"Failed to cache {key}, continuing without cache") + # Application continues normally +``` + +## Decision tree: How to handle errors + +```mermaid +graph LR + Start{Error occurred?} + + Start -->|Connection error| C1{Operation type?} + C1 -->|Read| C2["Graceful degradation
fallback"] + C1 -->|Write| C3["Log and continue
or retry"] + C1 -->|Critical| C4["Retry with backoff"] + + Start -->|Command error| Cmd1{Error source?} + Cmd1 -->|User input| Cmd2["Log and return
error to user"] + Cmd1 -->|Your code| Cmd3["Fail fast
fix the bug"] + + Start -->|Data error| D1{Operation type?} + D1 -->|Read| D2["Log, invalidate,
fallback"] + D1 -->|Write| D3["Log and fail
data is invalid"] + + Start -->|Resource error| R1{Error type?} + R1 -->|Redis loading| R2["Retry with backoff"] + R1 -->|Pool exhausted| R3["Increase pool size"] + R1 -->|Memory full| R4["Check configuration"] +``` + +## Logging and monitoring + +### What to log + +- **Error type and message:** What went wrong? +- **Context:** Which key? Which operation? +- **Timestamp:** When did it happen? +- **Retry information:** Is this a retry? How many attempts? + +**Example:** +```python +logger.error( + "Redis operation failed", + extra={ + "error_type": type(e).__name__, + "operation": "get", + "key": key, + "attempt": attempt, + "timestamp": datetime.now().isoformat(), + } +) +``` + +### What to monitor + +- **Error rate:** How many errors per minute? +- **Error types:** Which errors are most common? +- **Recovery success:** How many retries succeed? +- **Fallback usage:** How often do we use fallback strategies? + +These metrics help you identify patterns and potential issues. + +## Common mistakes + +### ❌ Catching all exceptions + +```python +try: + result = r.get(key) +except Exception: # Too broad! + pass +``` + +**Problem:** You might catch unexpected errors and hide bugs. + +**✅ Better:** +```python +try: + result = r.get(key) +except redis.ConnectionError: + # Handle connection error + pass +``` + +### ❌ Not distinguishing error types + +```python +try: + result = r.get(key) +except redis.ResponseError: + # Retry? This won't help if it's a syntax error! + retry() +``` + +**Problem:** Different errors need different handling. + +**✅ Better:** +```python +try: + result = r.get(key) +except redis.TimeoutError: + retry() # Retry on timeout +except redis.ResponseError: + raise # Fail on syntax error +``` + +### ❌ Retrying non-idempotent operations + +```python +# This increments the counter each retry! +for attempt in range(3): + try: + r.incr(counter) + break + except redis.TimeoutError: + pass # Retry +``` + +**Problem:** Retrying non-idempotent operations can cause data corruption. + +**✅ Better:** Only retry idempotent operations (GET, SET with same value) or use transactions. + +### ❌ Ignoring connection pool errors + +```python +# Pool is exhausted, but we don't handle it +result = r.get(key) # Might timeout waiting for connection +``` + +**Problem:** Connection pool errors indicate a configuration or concurrency issue. + +**✅ Better:** Monitor pool usage and increase size if needed. + +## Client-specific error handling + +For detailed information about exceptions in your client library, see: + +- [redis-py error handling]({{< relref "/develop/clients/redis-py/error-handling" >}}) +- [Node.js error handling]({{< relref "/develop/clients/nodejs/error-handling" >}}) +- [Java (Jedis) error handling]({{< relref "/develop/clients/jedis/error-handling" >}}) +- [Go (go-redis) error handling]({{< relref "/develop/clients/go/error-handling" >}}) +- [.NET (NRedisStack) error handling]({{< relref "/develop/clients/dotnet/error-handling" >}}) + +## Next steps + +- Learn about [connection pooling]({{< relref "/develop/clients/pools-and-muxing" >}}) to avoid resource errors +- Explore [client-side caching]({{< relref "/develop/clients/client-side-caching" >}}) for resilient applications +- See [use-case guides]({{< relref "/develop/use-cases" >}}) for pattern-specific error handling examples + From 38119d0167e1b5853494ccc26ef9f11053bf8284 Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Fri, 31 Oct 2025 15:41:05 +0000 Subject: [PATCH 03/16] DOC-5881 improved general error handling page --- content/develop/clients/error-handling.md | 47 +++++++++++++++-------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/content/develop/clients/error-handling.md b/content/develop/clients/error-handling.md index 33617eca52..db4fcc8417 100644 --- a/content/develop/clients/error-handling.md +++ b/content/develop/clients/error-handling.md @@ -9,6 +9,15 @@ When working with Redis, errors can occur for various reasons—network issues, ## Categories of errors +Redis errors fall into four main categories. The table below provides a quick overview of each type. Click on any error type to jump to its detailed section, which includes common causes, examples, handling strategies, and code examples. + +| Error Type | Common Causes | When to Handle | Examples | +|---|---|---|---| +| [Connection errors](#connection-errors) | Network issues, server down, auth failure, timeouts, pool exhaustion | Almost always | `ConnectionError`, `TimeoutError`, `AuthenticationError` | +| [Command errors](#command-errors) | Typo in command, wrong arguments, invalid types, unsupported command | Rarely (usually indicates a bug) | `ResponseError`, `WRONGTYPE`, `ERR unknown command` | +| [Data errors](#data-errors) | Serialization failures, corrupted data, type mismatches | Sometimes (depends on data source) | `JSONDecodeError`, `SerializationError`, `WRONGTYPE` | +| [Resource errors](#resource-errors) | Memory limit, pool exhausted, too many connections, key eviction | Sometimes (some are temporary) | `OOM`, pool timeout, `LOADING` | + ### Connection errors Connection errors occur when your application cannot communicate with Redis. These are typically temporary and often recoverable. @@ -29,7 +38,7 @@ Connection errors occur when your application cannot communicate with Redis. The **Example strategy:** -```mermaid {width="100%"} +```mermaid {width="80%"} graph TB A["Try to connect
to Redis"] A -->|Success| B(["Use the result"]) @@ -87,7 +96,7 @@ Data errors occur when there's a problem with the data itself—serialization fa **Example:** -```mermaid {width="60%"} +```mermaid {width="50%"} graph TB A["Read cached data"] A --> B["Try to deserialize"] @@ -270,8 +279,11 @@ These metrics help you identify patterns and potential issues. ## Common mistakes -### ❌ Catching all exceptions +### Catching all exceptions + +**Problem:** You might catch unexpected errors and hide bugs. +**Example (wrong):** ```python try: result = r.get(key) @@ -279,9 +291,9 @@ except Exception: # Too broad! pass ``` -**Problem:** You might catch unexpected errors and hide bugs. +**Better approach:** Catch specific exception types. -**✅ Better:** +**Example (correct):** ```python try: result = r.get(key) @@ -290,8 +302,11 @@ except redis.ConnectionError: pass ``` -### ❌ Not distinguishing error types +### Not distinguishing error types + +**Problem:** Different errors need different handling. Retrying a syntax error won't help. +**Example (wrong):** ```python try: result = r.get(key) @@ -300,9 +315,9 @@ except redis.ResponseError: retry() ``` -**Problem:** Different errors need different handling. +**Better approach:** Handle each error type differently based on whether it's recoverable. -**✅ Better:** +**Example (correct):** ```python try: result = r.get(key) @@ -312,8 +327,11 @@ except redis.ResponseError: raise # Fail on syntax error ``` -### ❌ Retrying non-idempotent operations +### Retrying non-idempotent operations +**Problem:** Retrying non-idempotent operations can cause data corruption. Each retry increments the counter again. + +**Example (wrong):** ```python # This increments the counter each retry! for attempt in range(3): @@ -324,20 +342,19 @@ for attempt in range(3): pass # Retry ``` -**Problem:** Retrying non-idempotent operations can cause data corruption. +**Better approach:** Only retry idempotent operations (GET, SET with same value) or use transactions. -**✅ Better:** Only retry idempotent operations (GET, SET with same value) or use transactions. +### Ignoring connection pool errors -### ❌ Ignoring connection pool errors +**Problem:** Connection pool errors indicate a configuration or concurrency issue that needs to be addressed. +**Example (wrong):** ```python # Pool is exhausted, but we don't handle it result = r.get(key) # Might timeout waiting for connection ``` -**Problem:** Connection pool errors indicate a configuration or concurrency issue. - -**✅ Better:** Monitor pool usage and increase size if needed. +**Better approach:** Monitor pool usage and increase size if needed. ## Client-specific error handling From ac4a8371d43a594b4fd53486ca0b436c81af5d13 Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Mon, 3 Nov 2025 10:34:11 +0000 Subject: [PATCH 04/16] DOC-5882 node-redis error handling page --- .../develop/clients/nodejs/error-handling.md | 159 ++++++++++++++++++ content/develop/clients/nodejs/produsage.md | 21 ++- 2 files changed, 178 insertions(+), 2 deletions(-) create mode 100644 content/develop/clients/nodejs/error-handling.md diff --git a/content/develop/clients/nodejs/error-handling.md b/content/develop/clients/nodejs/error-handling.md new file mode 100644 index 0000000000..544a16a3bb --- /dev/null +++ b/content/develop/clients/nodejs/error-handling.md @@ -0,0 +1,159 @@ +--- +title: Error handling +description: Learn how to handle errors when using node-redis. +linkTitle: Error handling +weight: 50 +--- + +node-redis uses +[**promises**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) +for error handling. Most Redis JavaScript examples +throughout the documentation mainly show the "happy path" and omit error +handling for brevity. This page shows how to apply error handling +techniques in node-redis for real world code. +For an overview of some common general error types and strategies for +handling them, see +[Error handling]({{< relref "/develop/clients/error-handling" >}}). +See also [Production usage]({{< relref "/develop/clients/nodejs/produsage" >}}) +for more information on connection management, timeouts, and other aspects of +app reliability. + + +## Common error types + +node-redis throws errors as rejected promises. Common error types include: + +| Error | When it occurs | Recoverable | Recommended action | +|---|---|---|---| +| `ECONNREFUSED` | Connection refused | ✅ | Retry with backoff or fall back | +| `ETIMEDOUT` | Command timeout | ✅ | Retry with backoff | +| `ECONNRESET` | Connection reset by peer | ✅ | Retry with backoff | +| `EAI_AGAIN` | DNS resolution failure | ✅ | Retry with backoff | +| `ReplyError` (`WRONGTYPE`) | Type mismatch | ❌ | Fix schema or code | +| `ReplyError` (`BUSY`, `TRYAGAIN`, `LOADING`) | Redis busy/loading | ⚠️ | Retry with backoff (bounded) | + +See [Categories of errors]({{< relref "/develop/clients/error-handling#categories-of-errors" >}}) +for a more detailed discussion of these errors and their causes. + +## Async/await in examples + +The examples on this page and throughout the node-redis docs use `async/await` +style for clarity. + +```javascript +// Using async/await (shown in examples below) +try { + const result = await client.get(key); + // Handle success +} catch (error) { + // Handle error +} +``` + +Alternatively, you can use promise chains with `.then()` and `.catch()`: + +```javascript +// Using promise chains (equivalent approach) +client.get(key) + .then(result => { + // Handle success + }) + .catch(error => { + // Handle error + }); +``` + +## Applying error handling patterns + +The [Error handling]({{< relref "/develop/clients/error-handling" >}}) +overview describes four common error handling patterns. The sections +below show how to implement these patterns in node-redis: + +### Pattern 1: Fail fast + +Catch specific errors and re-throw them (see +[Pattern 1: Fail fast]({{< relref "/develop/clients/error-handling#pattern-1-fail-fast" >}}) +for a full description). + +```javascript +try { + await client.get(key); +} catch (err) { + if (err.name === 'ReplyError' && /WRONGTYPE|ERR /.test(err.message)) { + throw err; // Fix code or data type + } + throw err; +} +``` + +### Pattern 2: Graceful degradation + +Catch connection errors and fall back to an alternative (see +[Pattern 2: Graceful degradation]({{< relref "/develop/clients/error-handling#pattern-2-graceful-degradation" >}}) +for a full description). + +```javascript +try { + const val = await client.get(key); + if (val != null) return val; +} catch (err) { + if (['ECONNREFUSED','ECONNRESET','ETIMEDOUT','EAI_AGAIN'].includes(err.code)) { + logger.warn('Cache unavailable; falling back to DB'); + return database.get(key); + } + throw err; +} +return database.get(key); +``` + +### Pattern 3: Retry with backoff + +Retry on temporary errors like timeouts (see +[Pattern 3: Retry with backoff]({{< relref "/develop/clients/error-handling#pattern-3-retry-with-backoff" >}}) +for a full description). + +```javascript +async function getWithRetry(key, { attempts = 3, baseDelayMs = 100 } = {}) { + let delay = baseDelayMs; + for (let i = 0; i < attempts; i++) { + try { + return await client.get(key); + } catch (err) { + if ( + i < attempts - 1 && + (['ETIMEDOUT','ECONNRESET','EAI_AGAIN'].includes(err.code) || + (err.name === 'ReplyError' && /(BUSY|TRYAGAIN|LOADING)/.test(err.message))) + ) { + await new Promise(r => setTimeout(r, delay)); + delay *= 2; + continue; + } + throw err; + } + } +} +``` + +### Pattern 4: Log and continue + +Log non-critical errors and continue (see +[Pattern 4: Log and continue]({{< relref "/develop/clients/error-handling#pattern-4-log-and-continue" >}}) +for a full description). + +```javascript +try { + await client.setEx(key, 3600, value); +} catch (err) { + if (['ECONNREFUSED','ECONNRESET','ETIMEDOUT','EAI_AGAIN'].includes(err.code)) { + logger.warn(`Failed to cache ${key}, continuing without cache`); + } else { + throw err; + } +} +``` + +## See also + +- [Error handling]({{< relref "/develop/clients/error-handling" >}}) +- [Production usage]({{< relref "/develop/clients/nodejs/produsage" >}}) +- [Connection pooling]({{< relref "/develop/clients/pools-and-muxing" >}}) diff --git a/content/develop/clients/nodejs/produsage.md b/content/develop/clients/nodejs/produsage.md index 992dc7c37e..dac681246c 100644 --- a/content/develop/clients/nodejs/produsage.md +++ b/content/develop/clients/nodejs/produsage.md @@ -27,7 +27,7 @@ progress in implementing the recommendations. {{< checklist "nodeprodlist" >}} {{< checklist-item "#handling-errors" >}}Handling errors{{< /checklist-item >}} {{< checklist-item "#handling-reconnections" >}}Handling reconnections{{< /checklist-item >}} - {{< checklist-item "#connection-timeouts" >}}Connection timeouts{{< /checklist-item >}} + {{< checklist-item "#timeouts" >}}Timeouts{{< /checklist-item >}} {{< checklist-item "#command-execution-reliability" >}}Command execution reliability{{< /checklist-item >}} {{< checklist-item "#seamless-client-experience" >}}Smart client handoffs{{< /checklist-item >}} {{< /checklist >}} @@ -65,7 +65,7 @@ own custom strategy. See [Reconnect after disconnection]({{< relref "/develop/clients/nodejs/connect#reconnect-after-disconnection" >}}) for more information. -### Connection timeouts +### Timeouts To set a timeout for a connection, use the `connectTimeout` option (the default timeout is 5 seconds): @@ -80,6 +80,23 @@ const client = createClient({ client.on('error', error => console.error('Redis client error:', error)); ``` +You can also set timeouts for individual commands using `AbortController`: + +```javascript +import { createClient, commandOptions } from 'redis'; + +const client = createClient({ url: 'redis://localhost:6379' }); +await client.connect(); + +const ac = new AbortController(); +const t = setTimeout(() => ac.abort(), 1000); +try { + const val = await client.get(commandOptions({ signal: ac.signal }), key); +} finally { + clearTimeout(t); +} +``` + ### Command execution reliability By default, `node-redis` reconnects automatically when the connection is lost From 4d32b3c2378802fcd51613cbbebd6835aa52c5a9 Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Mon, 3 Nov 2025 11:36:20 +0000 Subject: [PATCH 05/16] DOC-5881 redis-py error handling page --- .../clients/redis-py/error-handling.md | 163 ++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 content/develop/clients/redis-py/error-handling.md diff --git a/content/develop/clients/redis-py/error-handling.md b/content/develop/clients/redis-py/error-handling.md new file mode 100644 index 0000000000..bd2103bed9 --- /dev/null +++ b/content/develop/clients/redis-py/error-handling.md @@ -0,0 +1,163 @@ +--- +title: Error handling +description: Learn how to handle errors when using redis-py +linkTitle: Error handling +weight: 50 +--- + +redis-py uses **exceptions** to signal errors. The redis-py documentation mainly +shows the "happy path" in code examples and omits error handling for brevity. +This page explains how +redis-py's error handling works and how to apply common error handling patterns. +For an overview of error types and handling strategies, see +[Error handling]({{< relref "/develop/clients/error-handling" >}}). +See also [Production usage]({{< relref "/develop/clients/redis-py/produsage" >}}) +for more information on connection management, timeouts, and other aspects of +app reliability. + +## Exception hierarchy + +redis-py organizes exceptions in a hierarchy. The base exception is `redis.RedisError`, with specific subclasses for different error types: + +``` +RedisError (base) +├── ConnectionError +│ ├── TimeoutError +│ └── BusyLoadingError +├── ResponseError +├── InvalidResponse +├── DataError +├── PubSubError +└── ... (others) +``` + +### Key exceptions + +The following exceptions are the most commonly encountered in redis-py applications. +See +[Categories of errors]({{< relref "/develop/clients/error-handling#categories-of-errors" >}}) +for a more detailed discussion of these errors and their causes. + +| Exception | When it occurs | Recoverable | Recommended action | +|---|---|---|---| +| `redis.ConnectionError` | Network or connection issues | Yes | Retry with backoff or fall back to alternative | +| `redis.TimeoutError` | Operation exceeded timeout | Yes | Retry with backoff | +| `redis.ResponseError` | Invalid command or Redis error response | No | Fix the command or arguments | +| `redis.DataError` | Data serialization/deserialization issues | Sometimes | Log, invalidate cache, fetch fresh data | + +## Applying error handling patterns + +The [Error handling]({{< relref "/develop/clients/error-handling" >}}) overview +describes four main patterns. The sections below show how to implement them in +redis-py: + +### Pattern 1: Fail fast + +Catch specific exceptions and re-raise them (see +[Pattern 1: Fail fast]({{< relref "/develop/clients/error-handling#pattern-1-fail-fast" >}}) +for a full description): + +```python +import redis + +r = redis.Redis() + +try: + result = r.get(key) +except redis.ResponseError: + # This indicates a bug in our code + raise +``` + +### Pattern 2: Graceful degradation + +Catch connection errors and fall back to an alternative (see +[Pattern 2: Graceful degradation]({{< relref "/develop/clients/error-handling#pattern-2-graceful-degradation" >}}) +for a full description): + +```python +try: + cached_value = r.get(key) + if cached_value: + return cached_value +except redis.ConnectionError: + logger.warning("Cache unavailable, using database") + +# Fallback to database +return database.get(key) +``` + +### Pattern 3: Retry with backoff + +Retry on temporary errors like timeouts (see +[Pattern 3: Retry with backoff]({{< relref "/develop/clients/error-handling#pattern-3-retry-with-backoff" >}}) +for a full description): + +```python +import time + +max_retries = 3 +retry_delay = 0.1 + +for attempt in range(max_retries): + try: + return r.get(key) + except redis.TimeoutError: + if attempt < max_retries - 1: + time.sleep(retry_delay) + retry_delay *= 2 # Exponential backoff + else: + raise +``` + +### Pattern 4: Log and continue + +Log non-critical errors and continue (see +[Pattern 4: Log and continue]({{< relref "/develop/clients/error-handling#pattern-4-log-and-continue" >}}) +for a full description): + +```python +try: + r.setex(key, 3600, value) +except redis.ConnectionError: + logger.warning(f"Failed to cache {key}, continuing without cache") + # Application continues normally +``` + +## Async error handling + +If you're using `redis.asyncio`, error handling works the same way, but with `async`/`await`: + +```python +import redis.asyncio as redis + +async def get_with_fallback(key): + r = await redis.from_url("redis://localhost") + try: + return await r.get(key) + except redis.ConnectionError: + logger.warning("Cache unavailable") + return await database.get(key) + finally: + await r.close() +``` + +## Connection pool errors + +Connection pool exhaustion raises a `redis.ConnectionError`. Monitor pool usage +and adjust the pool size if necessary: + +```python +pool = redis.ConnectionPool( + host="localhost", + port=6379, + max_connections=50 # Adjust based on your needs +) +r = redis.Redis(connection_pool=pool) +``` + +## See also + +- [Error handling]({{< relref "/develop/clients/error-handling" >}}) +- [Production usage]({{< relref "/develop/clients/redis-py/produsage" >}}) +- [Connection pooling]({{< relref "/develop/clients/pools-and-muxing" >}}) From 05bf935d9bb0d3f9fb7bcfd7175fa49af4b09025 Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Mon, 3 Nov 2025 12:04:57 +0000 Subject: [PATCH 06/16] DOC-5885 go-redis error handling page --- content/develop/clients/go/error-handling.md | 167 +++++++++++++++++++ content/develop/clients/go/produsage.md | 3 + 2 files changed, 170 insertions(+) create mode 100644 content/develop/clients/go/error-handling.md diff --git a/content/develop/clients/go/error-handling.md b/content/develop/clients/go/error-handling.md new file mode 100644 index 0000000000..2059753c2a --- /dev/null +++ b/content/develop/clients/go/error-handling.md @@ -0,0 +1,167 @@ +--- +title: Error handling +description: Learn how to handle errors when using go-redis +linkTitle: Error handling +weight: 50 +--- + +go-redis uses **explicit error returns** following Go's idiomatic error handling pattern. Code examples in the documentation often omit error handling for brevity, +but it is essential in production code. +This page explains how go-redis's error handling works and how to apply +some common error handling patterns. For an overview of error types and handling +strategies, see [Error handling]({{< relref "/develop/clients/error-handling" >}}). +See also [Production usage]({{< relref "/develop/clients/go/produsage" >}}) +for more information on connection management, timeouts, and other aspects of +app reliability. + +## Error handling in Go + +In Go, functions return errors as a second return value. You can check for errors explicitly with code like the following: + +```go +result, err := rdb.Get(ctx, key).Result() +if err != nil { + // Handle the error +} +``` + +Common error types from go-redis include: + +| Error | When it occurs | Recoverable | Recommended action | +|---|---|---|---| +| `redis.Nil` | Key does not exist | Yes | Return default value or fetch from source | +| `context.DeadlineExceeded` | Operation timeout | Yes | Retry with backoff | +| `net.OpError` | Network error | Yes | Retry with backoff or fall back to alternative | +| `redis.ResponseError` | Redis error response | No | Fix the command or arguments | + +See [Categories of errors]({{< relref "/develop/clients/error-handling#categories-of-errors" >}}) +for a more detailed discussion of these errors and their causes. + +## Applying error handling patterns + +The [Error handling]({{< relref "/develop/clients/error-handling" >}}) overview +describes four main patterns. The sections below show how to implement them in +go-redis: + +### Pattern 1: Fail fast + +Return the error immediately (see +[Pattern 1: Fail fast]({{< relref "/develop/clients/error-handling#pattern-1-fail-fast" >}}) +for a full description): + +```go +result, err := rdb.Get(ctx, key).Result() +if err != nil { + // This indicates a problem that should be fixed + return err +} +``` + +### Pattern 2: Graceful degradation + +Check for specific errors and fall back to an alternative (see +[Pattern 2: Graceful degradation]({{< relref "/develop/clients/error-handling#pattern-2-graceful-degradation" >}}) +for a full description): + +```go +result, err := rdb.Get(ctx, key).Result() +if err != nil { + if err == redis.Nil { + // Key doesn't exist, try database + return database.Get(ctx, key) + } + if _, ok := err.(net.Error); ok { + // Network error, use fallback + logger.Warn("Cache unavailable, using database") + return database.Get(ctx, key) + } + return err +} +return result, nil +``` + +### Pattern 3: Retry with backoff + +Retry on temporary errors (see +[Pattern 3: Retry with backoff]({{< relref "/develop/clients/error-handling#pattern-3-retry-with-backoff" >}}) +for a full description): + +```go +import "time" + +func getWithRetry(ctx context.Context, key string, maxRetries int) (string, error) { + retryDelay := 100 * time.Millisecond + + for attempt := 0; attempt < maxRetries; attempt++ { + result, err := rdb.Get(ctx, key).Result() + if err == nil { + return result, nil + } + + // Check if error is temporary + if netErr, ok := err.(net.Error); ok && netErr.Timeout() { + if attempt < maxRetries-1 { + time.Sleep(retryDelay) + retryDelay *= 2 // Exponential backoff + continue + } + } + + return "", err + } + + return "", fmt.Errorf("max retries exceeded") +} +``` + +### Pattern 4: Log and continue + +Log non-critical errors and continue (see +[Pattern 4: Log and continue]({{< relref "/develop/clients/error-handling#pattern-4-log-and-continue" >}}) +for a full description): + +```go +err := rdb.SetEx(ctx, key, value, 3600*time.Second).Err() +if err != nil { + if _, ok := err.(net.Error); ok { + logger.Warnf("Failed to cache %s, continuing without cache", key) + // Application continues normally + } else { + return err + } +} +``` + +## Connection pool errors + +go-redis manages a connection pool automatically. If the pool is exhausted, operations will timeout. You can configure the pool size to avoid this if +necessary: + +```go +rdb := redis.NewClient(&redis.Options{ + Addr: "localhost:6379", + PoolSize: 10, // Number of connections +}) +``` + +## Context-based cancellation + +go-redis respects context cancellation. Use context timeouts for error handling: + +```go +ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) +defer cancel() + +result, err := rdb.Get(ctx, key).Result() +if err == context.DeadlineExceeded { + logger.Warn("Operation timeout") + // Handle timeout +} +``` + +## See also + +- [Error handling]({{< relref "/develop/clients/error-handling" >}}) +- [Production usage]({{< relref "/develop/clients/go/produsage" >}}) +- [Connection pooling]({{< relref "/develop/clients/pools-and-muxing" >}}) + diff --git a/content/develop/clients/go/produsage.md b/content/develop/clients/go/produsage.md index 80b11cfa0f..7745395088 100644 --- a/content/develop/clients/go/produsage.md +++ b/content/develop/clients/go/produsage.md @@ -64,6 +64,9 @@ you should also always check that the error value is `nil` before proceeding. Errors can be returned for failed connections, network problems, and invalid command parameters, among other things. +See [Error handling]({{< relref "/develop/clients/go/error-handling" >}}) for a +more detailed discussion of error handling approaches in `go-redis`. + ### Monitor performance and errors `go-redis` supports [OpenTelemetry](https://opentelemetry.io/). This lets From ecae0bbaf0a959fe2492bc87984577a903f87e10 Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Mon, 3 Nov 2025 13:47:47 +0000 Subject: [PATCH 07/16] DOC-5882 link to error handling page from prod usage page --- content/develop/clients/nodejs/produsage.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/content/develop/clients/nodejs/produsage.md b/content/develop/clients/nodejs/produsage.md index dac681246c..c15b2be646 100644 --- a/content/develop/clients/nodejs/produsage.md +++ b/content/develop/clients/nodejs/produsage.md @@ -55,6 +55,8 @@ client.on('error', error => { }); ``` +See also [Error handling]({{< relref "/develop/clients/nodejs/error-handling" >}}) for a more detailed discussion of error handling approaches in `node-redis`. + ### Handling reconnections When the socket closes unexpectedly (without calling the `quit()` or `disconnect()` methods), From 0216a51c2ad84638bbaf6a51af9f1c9a6388b757 Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Mon, 3 Nov 2025 14:44:14 +0000 Subject: [PATCH 08/16] DOC-5886 C# error handling page --- .../develop/clients/dotnet/error-handling.md | 147 ++++++++++++++++++ content/develop/clients/dotnet/produsage.md | 3 + content/develop/clients/error-handling.md | 1 - 3 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 content/develop/clients/dotnet/error-handling.md diff --git a/content/develop/clients/dotnet/error-handling.md b/content/develop/clients/dotnet/error-handling.md new file mode 100644 index 0000000000..03bd8f7501 --- /dev/null +++ b/content/develop/clients/dotnet/error-handling.md @@ -0,0 +1,147 @@ +--- +title: Error handling +description: Learn how to handle errors when using NRedisStack. +linkTitle: Error handling +weight: 60 +--- + +NRedisStack uses **exceptions** to signal errors. Code examples in the documentation often omit error handling for brevity, but it is essential in production code. This page explains how NRedisStack's error handling works and how to apply common error handling patterns. + +For an overview of error types and handling strategies, see [Error handling]({{< relref "/develop/clients/error-handling" >}}). +See also [Production usage]({{< relref "/develop/clients/dotnet/produsage" >}}) +for more information on connection management, timeouts, and other aspects of +app reliability. + +## Exception types + +NRedisStack throws exceptions to signal errors. Common exception types include: + +| Exception | When it occurs | Recoverable | Recommended action | +|---|---|---|---| +| `RedisConnectionException` | Connection refused or lost | ✅ | Retry with backoff or fall back | +| `RedisTimeoutException` | Operation exceeded timeout | ✅ | Retry with backoff | +| `RedisCommandException` | Invalid command or arguments | ❌ | Fix the command or arguments | +| `RedisServerException` | Invalid operation on server | ❌ | Fix the operation or data | + +See [Categories of errors]({{< relref "/develop/clients/error-handling#categories-of-errors" >}}) +for a more detailed discussion of these errors and their causes. + +## Applying error handling patterns + +The [Error handling]({{< relref "/develop/clients/error-handling" >}}) overview +describes four main patterns. The sections below show how to implement them in +NRedisStack: + +### Pattern 1: Fail fast + +Catch specific exceptions that represent unrecoverable errors and re-throw them (see +[Pattern 1: Fail fast]({{< relref "/develop/clients/error-handling#pattern-1-fail-fast" >}}) +for a full description): + +```csharp +using NRedisStack; +using StackExchange.Redis; + +var muxer = ConnectionMultiplexer.Connect("localhost:6379"); +var db = muxer.GetDatabase(); + +try { + var result = db.StringGet("key"); +} catch (RedisCommandException) { + // This indicates a bug in our code + throw; +} +``` + +### Pattern 2: Graceful degradation + +Catch specific errors and fall back to an alternative, where possible (see +[Pattern 2: Graceful degradation]({{< relref "/develop/clients/error-handling#pattern-2-graceful-degradation" >}}) +for a full description): + +```csharp +try { + var cachedValue = db.StringGet(key); + if (cachedValue.HasValue) { + return cachedValue.ToString(); + } +} catch (RedisConnectionException) { + logger.LogWarning("Cache unavailable, using database"); + return database.Get(key); +} + +// Fallback to database +return database.Get(key); +``` + +### Pattern 3: Retry with backoff + +Retry on temporary errors like timeouts (see +[Pattern 3: Retry with backoff]({{< relref "/develop/clients/error-handling#pattern-3-retry-with-backoff" >}}) +for a full description): + +```csharp +const int maxRetries = 3; +int retryDelay = 100; + +for (int attempt = 0; attempt < maxRetries; attempt++) { + try { + return db.StringGet(key).ToString(); + } catch (RedisTimeoutException) { + if (attempt < maxRetries - 1) { + Thread.Sleep(retryDelay); + retryDelay *= 2; // Exponential backoff + } else { + throw; + } + } +} +``` + +### Pattern 4: Log and continue + +Log non-critical errors and continue (see +[Pattern 4: Log and continue]({{< relref "/develop/clients/error-handling#pattern-4-log-and-continue" >}}) +for a full description): + +```csharp +try { + db.StringSet(key, value, TimeSpan.FromSeconds(3600)); +} catch (RedisConnectionException) { + logger.LogWarning($"Failed to cache {key}, continuing without cache"); + // Application continues normally +} +``` + +## Async error handling + +If you're using async methods, error handling works the same way with `async`/`await`: + +```csharp +using NRedisStack; +using StackExchange.Redis; + +var muxer = ConnectionMultiplexer.Connect("localhost:6379"); +var db = muxer.GetDatabase(); + +async Task GetWithFallbackAsync(string key) { + try { + var result = await db.StringGetAsync(key); + if (result.HasValue) { + return result.ToString(); + } + } catch (RedisConnectionException) { + logger.LogWarning("Cache unavailable"); + return await database.GetAsync(key); + } + + return await database.GetAsync(key); +} +``` + +## See also + +- [Error handling]({{< relref "/develop/clients/error-handling" >}}) +- [Production usage]({{< relref "/develop/clients/dotnet/produsage" >}}) +- [Connection pooling]({{< relref "/develop/clients/pools-and-muxing" >}}) + diff --git a/content/develop/clients/dotnet/produsage.md b/content/develop/clients/dotnet/produsage.md index 1dc8d5a8d0..4068f122c6 100644 --- a/content/develop/clients/dotnet/produsage.md +++ b/content/develop/clients/dotnet/produsage.md @@ -112,6 +112,9 @@ the most common Redis exceptions: [stream entry]({{< relref "/develop/data-types/streams#entry-ids" >}}) using an invalid ID). +See [Error handling]({{< relref "/develop/clients/dotnet/error-handling" >}}) +for more information on handling exceptions. + ### Retries During the initial `ConnectionMultiplexer.Connect()` call, `NRedisStack` will diff --git a/content/develop/clients/error-handling.md b/content/develop/clients/error-handling.md index db4fcc8417..be39edf9bc 100644 --- a/content/develop/clients/error-handling.md +++ b/content/develop/clients/error-handling.md @@ -371,4 +371,3 @@ For detailed information about exceptions in your client library, see: - Learn about [connection pooling]({{< relref "/develop/clients/pools-and-muxing" >}}) to avoid resource errors - Explore [client-side caching]({{< relref "/develop/clients/client-side-caching" >}}) for resilient applications - See [use-case guides]({{< relref "/develop/use-cases" >}}) for pattern-specific error handling examples - From 7352dc58832db3cd933b1840100479568aff43e5 Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Mon, 3 Nov 2025 15:25:16 +0000 Subject: [PATCH 09/16] DOC-5883n Jedis error handling page --- .../develop/clients/jedis/error-handling.md | 139 ++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 content/develop/clients/jedis/error-handling.md diff --git a/content/develop/clients/jedis/error-handling.md b/content/develop/clients/jedis/error-handling.md new file mode 100644 index 0000000000..f272306d9f --- /dev/null +++ b/content/develop/clients/jedis/error-handling.md @@ -0,0 +1,139 @@ +--- +title: Error handling +description: Learn how to handle errors when using Jedis. +linkTitle: Error handling +weight: 50 +--- + +Jedis uses **exceptions** to signal errors. Code examples in the documentation often omit error handling for brevity, but it is essential in production code. This page explains how Jedis's error handling works and how to apply common error handling patterns. + +For an overview of error types and handling strategies, see [Error handling]({{< relref "/develop/clients/error-handling" >}}). +See also [Production usage]({{< relref "/develop/clients/jedis/produsage" >}}) +for more information on connection management, timeouts, and other aspects of +app reliability. + +## Exception hierarchy + +Jedis organizes exceptions in a hierarchy rooted at `JedisException`, which extends `RuntimeException`. All Jedis exceptions are unchecked exceptions: + +``` +JedisException +├── JedisDataException +│ ├── JedisRedirectionException +│ │ ├── JedisMovedDataException +│ │ └── JedisAskDataException +│ ├── AbortedTransactionException +│ ├── JedisAccessControlException +│ └── JedisNoScriptException +├── JedisClusterException +│ ├── JedisClusterOperationException +│ ├── JedisConnectionException +│ └── JedisValidationException +└── InvalidURIException +``` + +### Key exceptions + +The following exceptions are the most commonly encountered in Jedis applications. +See [Categories of errors]({{< relref "/develop/clients/error-handling#categories-of-errors" >}}) +for a more detailed discussion of these errors and their causes. + +| Exception | When it occurs | Recoverable | Recommended action | +|---|---|---|---| +| `JedisConnectionException` | Connection lost or closed unexpectedly | ✅ | Retry with backoff or fall back | +| `JedisAccessControlException` | Authentication failure or permission denied | ❌ | Fix credentials or permissions | +| `JedisDataException` | Problem with data being sent or received | ❌ | Fix the data or command | +| `JedisException` | Unexpected errors (catch-all) | ❌ | Log and investigate | + +## Applying error handling patterns + +The [Error handling]({{< relref "/develop/clients/error-handling" >}}) overview +describes four main patterns. The sections below show how to implement them in +Jedis: + +### Pattern 1: Fail fast + +Catch specific exceptions that represent unrecoverable errors and re-throw them (see +[Pattern 1: Fail fast]({{< relref "/develop/clients/error-handling#pattern-1-fail-fast" >}}) +for a full description): + +```java +try (Jedis jedis = jedisPool.getResource()) { + String result = jedis.get(key); +} catch (JedisDataException e) { + // This indicates a bug in our code + throw e; +} +``` + +### Pattern 2: Graceful degradation + +Catch specific errors and fall back to an alternative, where possible (see +[Pattern 2: Graceful degradation]({{< relref "/develop/clients/error-handling#pattern-2-graceful-degradation" >}}) +for a full description): + +```java +try (Jedis jedis = jedisPool.getResource()) { + String cachedValue = jedis.get(key); + if (cachedValue != null) { + return cachedValue; + } +} catch (JedisConnectionException e) { + logger.warn("Cache unavailable, using database"); + return database.get(key); +} + +// Fallback to database +return database.get(key); +``` + +### Pattern 3: Retry with backoff + +Retry on temporary errors like connection failures (see +[Pattern 3: Retry with backoff]({{< relref "/develop/clients/error-handling#pattern-3-retry-with-backoff" >}}) +for a full description): + +```java +int maxRetries = 3; +int retryDelay = 100; + +for (int attempt = 0; attempt < maxRetries; attempt++) { + try (Jedis jedis = jedisPool.getResource()) { + return jedis.get(key); + } catch (JedisConnectionException e) { + if (attempt < maxRetries - 1) { + try { + Thread.sleep(retryDelay); + retryDelay *= 2; // Exponential backoff + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + throw new RuntimeException(ie); + } + } else { + throw e; + } + } +} +``` + +### Pattern 4: Log and continue + +Log non-critical errors and continue (see +[Pattern 4: Log and continue]({{< relref "/develop/clients/error-handling#pattern-4-log-and-continue" >}}) +for a full description): + +```java +try (Jedis jedis = jedisPool.getResource()) { + jedis.setex(key, 3600, value); +} catch (JedisConnectionException e) { + logger.warn("Failed to cache " + key + ", continuing without cache"); + // Application continues normally +} +``` + +## See also + +- [Error handling]({{< relref "/develop/clients/error-handling" >}}) +- [Production usage]({{< relref "/develop/clients/jedis/produsage" >}}) +- [Connection pooling]({{< relref "/develop/clients/pools-and-muxing" >}}) + From 8ebfc683a85c8a11abd567abc2c142d1db3dbf2c Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Tue, 4 Nov 2025 14:03:47 +0000 Subject: [PATCH 10/16] DOC-5880 improved main error handling page --- content/develop/clients/error-handling.md | 86 ++++++++++++----------- 1 file changed, 46 insertions(+), 40 deletions(-) diff --git a/content/develop/clients/error-handling.md b/content/develop/clients/error-handling.md index be39edf9bc..38e6919b9e 100644 --- a/content/develop/clients/error-handling.md +++ b/content/develop/clients/error-handling.md @@ -1,11 +1,11 @@ --- title: Error handling -description: Learn how to handle errors when using Redis client libraries +description: Learn how to handle errors when using Redis client libraries. linkTitle: Error handling weight: 50 --- -When working with Redis, errors can occur for various reasons—network issues, invalid commands, or resource constraints. This guide explains the types of errors you might encounter and how to handle them effectively. +When working with Redis, errors can occur for various reasons, including network issues, invalid commands, or resource constraints. This guide explains the types of errors you might encounter and how to handle them effectively. ## Categories of errors @@ -53,17 +53,20 @@ graph TB Command errors occur when Redis receives an invalid or malformed command. These typically indicate a bug in your code. **Common causes:** -- Typo in command name -- Wrong number of arguments -- Invalid argument types -- Using a command that doesn't exist in your Redis version +- Typo in command name +- Wrong number of arguments +- Invalid argument types (for example, supplying a [string]({{< relref "/develop/ + data-types/strings" >}}) key to a [list]({{< relref "/develop/data-types/lists" + >}}) command)) +- Using a command that doesn't exist in your Redis version **Examples:** - `ResponseError`: Invalid command or syntax error - `WRONGTYPE Operation against a key holding the wrong kind of value` - `ERR unknown command` -**When to handle:** Rarely. These usually indicate a programming error and should be fixed in your code, not handled at runtime. However, some cases (like invalid user input) may warrant handling. +**When to handle:** Rarely. These usually indicate programming error and so you +should fix the errors in your code rather than attempt to handle them at runtime. However, some cases (like invalid user input) may be worth handling. **Example:** @@ -79,18 +82,17 @@ graph TB ### Data errors -Data errors occur when there's a problem with the data itself—serialization failures, corrupted data, or type mismatches. +Data errors occur when there are problems with the data itself, such as +serialization failures, or data corruption. **Common causes:** - Object cannot be serialized to JSON - Cached data is corrupted - Attempting to deserialize invalid data -- Type mismatch (e.g., trying to use string operations on a list) **Examples:** - `JSONDecodeError`: Cannot deserialize JSON data - `SerializationError`: Cannot serialize object -- `WRONGTYPE`: Operating on wrong data type **When to handle:** Sometimes. If the error is due to user input or external data, handle it gracefully. If it's due to your code, fix the code. @@ -140,11 +142,13 @@ graph TB Use this when the error is unrecoverable or indicates a bug in your code. **When to use:** + - Command errors (invalid syntax) - Authentication errors - Programming errors **Example:** + ```python try: result = r.get(key) @@ -155,14 +159,17 @@ except redis.ResponseError as e: ### Pattern 2: Graceful degradation -Use this when you have an alternative way to get the data. +Use this when you have an alternative way to get the data you need, so you can +fall back to using the alternative instead of the preferred code. **When to use:** + - Cache reads (fallback to database) - Session reads (fallback to default values) - Optional data (skip if unavailable) **Example:** + ```python try: cached_value = r.get(key) @@ -177,14 +184,17 @@ return database.get(key) ### Pattern 3: Retry with backoff -Use this when the error is temporary and the operation is idempotent. +Use this when the error could be due to network load or other temporary +conditions. **When to use:** + - Connection timeouts - Temporary network issues - Redis loading data **Example:** + ```python import time @@ -202,16 +212,23 @@ for attempt in range(max_retries): raise ``` +Note that client libraries often implement retry logic for you, so +you may just need to provide the right configuration rather than +implementing retries yourself. See [Client-specific error handling](#client-specific-error-handling) below for links to pages that +describe retry configuration for each client library. + ### Pattern 4: Log and continue Use this when the operation is not critical to your application. **When to use:** + - Cache writes (data loss is acceptable) - Non-critical updates - Metrics collection **Example:** + ```python try: r.setex(key, 3600, value) @@ -247,6 +264,11 @@ graph LR ## Logging and monitoring +In production, you may find it useful to log errors when they +occur and monitor the logs for patterns. This can help you identify +which errors are most common and whether your retry and fallback +strategies are effective. + ### What to log - **Error type and message:** What went wrong? @@ -281,19 +303,22 @@ These metrics help you identify patterns and potential issues. ### Catching all exceptions -**Problem:** You might catch unexpected errors and hide bugs. +**Problem:** If you catch all exceptions, you might catch unexpected +errors and hide bugs. **Example (wrong):** + ```python try: result = r.get(key) -except Exception: # Too broad! +except Exception: # Too broad - some errors indicate code problems. pass ``` **Better approach:** Catch specific exception types. **Example (correct):** + ```python try: result = r.get(key) @@ -304,20 +329,23 @@ except redis.ConnectionError: ### Not distinguishing error types -**Problem:** Different errors need different handling. Retrying a syntax error won't help. +**Problem:** Different errors need different handling. For example, retrying a syntax error won't help. **Example (wrong):** + ```python try: result = r.get(key) except redis.ResponseError: - # Retry? This won't help if it's a syntax error! + # Retry? This won't help if it's a syntax error. retry() ``` -**Better approach:** Handle each error type differently based on whether it's recoverable. +**Better approach:** Handle each error type differently based on whether or not +it is recoverable. **Example (correct):** + ```python try: result = r.get(key) @@ -327,28 +355,12 @@ except redis.ResponseError: raise # Fail on syntax error ``` -### Retrying non-idempotent operations - -**Problem:** Retrying non-idempotent operations can cause data corruption. Each retry increments the counter again. - -**Example (wrong):** -```python -# This increments the counter each retry! -for attempt in range(3): - try: - r.incr(counter) - break - except redis.TimeoutError: - pass # Retry -``` - -**Better approach:** Only retry idempotent operations (GET, SET with same value) or use transactions. - ### Ignoring connection pool errors **Problem:** Connection pool errors indicate a configuration or concurrency issue that needs to be addressed. **Example (wrong):** + ```python # Pool is exhausted, but we don't handle it result = r.get(key) # Might timeout waiting for connection @@ -365,9 +377,3 @@ For detailed information about exceptions in your client library, see: - [Java (Jedis) error handling]({{< relref "/develop/clients/jedis/error-handling" >}}) - [Go (go-redis) error handling]({{< relref "/develop/clients/go/error-handling" >}}) - [.NET (NRedisStack) error handling]({{< relref "/develop/clients/dotnet/error-handling" >}}) - -## Next steps - -- Learn about [connection pooling]({{< relref "/develop/clients/pools-and-muxing" >}}) to avoid resource errors -- Explore [client-side caching]({{< relref "/develop/clients/client-side-caching" >}}) for resilient applications -- See [use-case guides]({{< relref "/develop/use-cases" >}}) for pattern-specific error handling examples From 293a1d15a694c9a0bec397383855d8a4245e32bf Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Tue, 4 Nov 2025 15:08:32 +0000 Subject: [PATCH 11/16] DOC-5886 improved C# error handling page --- .../develop/clients/dotnet/error-handling.md | 22 +++++++++---------- content/develop/clients/error-handling.md | 6 ++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/content/develop/clients/dotnet/error-handling.md b/content/develop/clients/dotnet/error-handling.md index 03bd8f7501..965a97f477 100644 --- a/content/develop/clients/dotnet/error-handling.md +++ b/content/develop/clients/dotnet/error-handling.md @@ -48,7 +48,8 @@ var db = muxer.GetDatabase(); try { var result = db.StringGet("key"); } catch (RedisCommandException) { - // This indicates a bug in our code + // This indicates a bug in the code, such as using + // StringGet on a list key. throw; } ``` @@ -62,21 +63,18 @@ for a full description): ```csharp try { var cachedValue = db.StringGet(key); - if (cachedValue.HasValue) { - return cachedValue.ToString(); - } + return cachedValue.ToString(); } catch (RedisConnectionException) { logger.LogWarning("Cache unavailable, using database"); + + // Fallback to database return database.Get(key); } - -// Fallback to database -return database.Get(key); ``` ### Pattern 3: Retry with backoff -Retry on temporary errors like timeouts (see +Retry on temporary errors such as timeouts (see [Pattern 3: Retry with backoff]({{< relref "/develop/clients/error-handling#pattern-3-retry-with-backoff" >}}) for a full description): @@ -98,6 +96,9 @@ for (int attempt = 0; attempt < maxRetries; attempt++) { } ``` +See also [Timeouts]({{< relref "/develop/clients/dotnet/produsage#timeouts" >}}) +for more information on configuring timeouts in NRedisStack. + ### Pattern 4: Log and continue Log non-critical errors and continue (see @@ -115,7 +116,8 @@ try { ## Async error handling -If you're using async methods, error handling works the same way with `async`/`await`: +Error handling works the usual way with `async`/`await`, as shown in the +example below: ```csharp using NRedisStack; @@ -143,5 +145,3 @@ async Task GetWithFallbackAsync(string key) { - [Error handling]({{< relref "/develop/clients/error-handling" >}}) - [Production usage]({{< relref "/develop/clients/dotnet/produsage" >}}) -- [Connection pooling]({{< relref "/develop/clients/pools-and-muxing" >}}) - diff --git a/content/develop/clients/error-handling.md b/content/develop/clients/error-handling.md index 38e6919b9e..1a81fb0d2f 100644 --- a/content/develop/clients/error-handling.md +++ b/content/develop/clients/error-handling.md @@ -55,9 +55,9 @@ Command errors occur when Redis receives an invalid or malformed command. These **Common causes:** - Typo in command name - Wrong number of arguments -- Invalid argument types (for example, supplying a [string]({{< relref "/develop/ - data-types/strings" >}}) key to a [list]({{< relref "/develop/data-types/lists" - >}}) command)) +- Invalid argument types (for example, supplying a + [string]({{< relref "/develop/data-types/strings" >}}) key to a + [list]({{< relref "/develop/data-types/lists" >}}) command)) - Using a command that doesn't exist in your Redis version **Examples:** From d407ed9b945e79773362abd68c648614bd68a996 Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Tue, 4 Nov 2025 15:49:16 +0000 Subject: [PATCH 12/16] DOC-5885 improved Go error handling page --- content/develop/clients/go/error-handling.md | 66 +++----------------- 1 file changed, 8 insertions(+), 58 deletions(-) diff --git a/content/develop/clients/go/error-handling.md b/content/develop/clients/go/error-handling.md index 2059753c2a..35e4ae6a5d 100644 --- a/content/develop/clients/go/error-handling.md +++ b/content/develop/clients/go/error-handling.md @@ -82,37 +82,12 @@ return result, nil ### Pattern 3: Retry with backoff -Retry on temporary errors (see +Retry on temporary errors such as timeouts (see [Pattern 3: Retry with backoff]({{< relref "/develop/clients/error-handling#pattern-3-retry-with-backoff" >}}) -for a full description): - -```go -import "time" - -func getWithRetry(ctx context.Context, key string, maxRetries int) (string, error) { - retryDelay := 100 * time.Millisecond - - for attempt := 0; attempt < maxRetries; attempt++ { - result, err := rdb.Get(ctx, key).Result() - if err == nil { - return result, nil - } - - // Check if error is temporary - if netErr, ok := err.(net.Error); ok && netErr.Timeout() { - if attempt < maxRetries-1 { - time.Sleep(retryDelay) - retryDelay *= 2 // Exponential backoff - continue - } - } - - return "", err - } - - return "", fmt.Errorf("max retries exceeded") -} -``` +for a full description). go-redis has built-in retry logic with +configurable timing and backoffs. See [Retries]({{< relref "/develop/clients/go/produsage#retries" >}}) for more information. Note also that +you can configure timeouts (which are one of the most common causes of +temporary errors) for connections and commands. See [Timeouts]({{< relref "/develop/clients/go/produsage#timeouts" >}}) for more information. ### Pattern 4: Log and continue @@ -132,36 +107,11 @@ if err != nil { } ``` -## Connection pool errors - -go-redis manages a connection pool automatically. If the pool is exhausted, operations will timeout. You can configure the pool size to avoid this if -necessary: - -```go -rdb := redis.NewClient(&redis.Options{ - Addr: "localhost:6379", - PoolSize: 10, // Number of connections -}) -``` - -## Context-based cancellation - -go-redis respects context cancellation. Use context timeouts for error handling: - -```go -ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) -defer cancel() - -result, err := rdb.Get(ctx, key).Result() -if err == context.DeadlineExceeded { - logger.Warn("Operation timeout") - // Handle timeout -} -``` +Note that go-redis also supports [OpenTelemetry](https://opentelemetry.io/) +instrumentation to monitor performance and trace the execution of Redis commands. See [Observability]({{< relref "/develop/clients/go#observability" >}}) for more information. ## See also - [Error handling]({{< relref "/develop/clients/error-handling" >}}) - [Production usage]({{< relref "/develop/clients/go/produsage" >}}) -- [Connection pooling]({{< relref "/develop/clients/pools-and-muxing" >}}) - +- [Observability]({{< relref "/develop/clients/go#observability" >}}) From fd9e48a4015d859e8dbd8be3e06a03251ae185e1 Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Tue, 4 Nov 2025 16:00:53 +0000 Subject: [PATCH 13/16] DOC-5883 improved Jedis error handling page --- content/develop/clients/jedis/error-handling.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/content/develop/clients/jedis/error-handling.md b/content/develop/clients/jedis/error-handling.md index f272306d9f..528a6ed082 100644 --- a/content/develop/clients/jedis/error-handling.md +++ b/content/develop/clients/jedis/error-handling.md @@ -135,5 +135,3 @@ try (Jedis jedis = jedisPool.getResource()) { - [Error handling]({{< relref "/develop/clients/error-handling" >}}) - [Production usage]({{< relref "/develop/clients/jedis/produsage" >}}) -- [Connection pooling]({{< relref "/develop/clients/pools-and-muxing" >}}) - From afdd9b088ee9508d4b3d7850c41f05a50dbe5afe Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Tue, 4 Nov 2025 16:30:27 +0000 Subject: [PATCH 14/16] DOC-5882 improve node-redis error handling page --- .../develop/clients/nodejs/error-handling.md | 29 +++++++++++++++++-- content/develop/clients/nodejs/migration.md | 2 +- content/develop/clients/nodejs/produsage.md | 24 ++++----------- 3 files changed, 33 insertions(+), 22 deletions(-) diff --git a/content/develop/clients/nodejs/error-handling.md b/content/develop/clients/nodejs/error-handling.md index 544a16a3bb..520f0781d4 100644 --- a/content/develop/clients/nodejs/error-handling.md +++ b/content/develop/clients/nodejs/error-handling.md @@ -2,7 +2,7 @@ title: Error handling description: Learn how to handle errors when using node-redis. linkTitle: Error handling -weight: 50 +weight: 6 --- node-redis uses @@ -63,6 +63,27 @@ client.get(key) }); ``` +## Error events + +Node-Redis provides [multiple events to handle various scenarios](https://github.com/redis/node-redis?tab=readme-ov-file#events), among which the most critical is the `error` event. + +This event is triggered whenever an error occurs within the client. + +It is crucial to listen for error events. + +If a client does not register at least one error listener and an error occurs, the system will throw that error, potentially causing the Node.js process to exit unexpectedly. +See [the EventEmitter docs](https://nodejs.org/api/events.html#events_error_events) for more details. + +```typescript +const client = createClient({ + // ... client options +}); +// Always ensure there's a listener for errors in the client to prevent process crashes due to unhandled errors +client.on('error', error => { + console.error(`Redis client error:`, error); +}); +``` + ## Applying error handling patterns The [Error handling]({{< relref "/develop/clients/error-handling" >}}) @@ -134,6 +155,11 @@ async function getWithRetry(key, { attempts = 3, baseDelayMs = 100 } = {}) { } ``` +Note that you can also configure node-redis to reconnect to the +server automatically when the connection is lost. See +[Reconnect after disconnection]({{< relref "/develop/clients/nodejs/connect#reconnect-after-disconnection" >}}) +for more information. + ### Pattern 4: Log and continue Log non-critical errors and continue (see @@ -156,4 +182,3 @@ try { - [Error handling]({{< relref "/develop/clients/error-handling" >}}) - [Production usage]({{< relref "/develop/clients/nodejs/produsage" >}}) -- [Connection pooling]({{< relref "/develop/clients/pools-and-muxing" >}}) diff --git a/content/develop/clients/nodejs/migration.md b/content/develop/clients/nodejs/migration.md index f187f61853..3abfb79055 100644 --- a/content/develop/clients/nodejs/migration.md +++ b/content/develop/clients/nodejs/migration.md @@ -12,7 +12,7 @@ categories: description: Discover the differences between `ioredis` and `node-redis`. linkTitle: Migrate from ioredis title: Migrate from ioredis -weight: 6 +weight: 10 --- Redis previously recommended the [`ioredis`](https://github.com/redis/ioredis) diff --git a/content/develop/clients/nodejs/produsage.md b/content/develop/clients/nodejs/produsage.md index c15b2be646..f060046047 100644 --- a/content/develop/clients/nodejs/produsage.md +++ b/content/develop/clients/nodejs/produsage.md @@ -12,7 +12,7 @@ categories: description: Get your Node.js app ready for production linkTitle: Production usage title: Production usage -weight: 5 +weight: 8 --- This guide offers recommendations to get the best reliability and @@ -38,24 +38,10 @@ progress in implementing the recommendations. Node-Redis provides [multiple events to handle various scenarios](https://github.com/redis/node-redis?tab=readme-ov-file#events), among which the most critical is the `error` event. -This event is triggered whenever an error occurs within the client. - -It is crucial to listen for error events. - -If a client does not register at least one error listener and an error occurs, the system will throw that error, potentially causing the Node.js process to exit unexpectedly. -See [the EventEmitter docs](https://nodejs.org/api/events.html#events_error_events) for more details. - -```typescript -const client = createClient({ - // ... client options -}); -// Always ensure there's a listener for errors in the client to prevent process crashes due to unhandled errors -client.on('error', error => { - console.error(`Redis client error:`, error); -}); -``` - -See also [Error handling]({{< relref "/develop/clients/nodejs/error-handling" >}}) for a more detailed discussion of error handling approaches in `node-redis`. +This event is triggered whenever an error occurs within the client, and +it is very important to set a handler to listen for it. +See [Error events]({{< relref "/develop/clients/nodejs/error-handling#error-events" >}}) +for more information and an example of setting an error handler. ### Handling reconnections From 60162f06fda222d77648594b6e791eb80e7441fb Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Wed, 5 Nov 2025 10:49:59 +0000 Subject: [PATCH 15/16] DOC-5880 last (maybe) fixes to client-specific error pages --- content/develop/clients/go/error-handling.md | 2 +- .../develop/clients/nodejs/error-handling.md | 2 +- .../clients/redis-py/error-handling.md | 48 +++++-------------- 3 files changed, 13 insertions(+), 39 deletions(-) diff --git a/content/develop/clients/go/error-handling.md b/content/develop/clients/go/error-handling.md index 35e4ae6a5d..9032a5be7b 100644 --- a/content/develop/clients/go/error-handling.md +++ b/content/develop/clients/go/error-handling.md @@ -45,7 +45,7 @@ go-redis: ### Pattern 1: Fail fast -Return the error immediately (see +Return the error immediately if it represents an unrecoverable situation (see [Pattern 1: Fail fast]({{< relref "/develop/clients/error-handling#pattern-1-fail-fast" >}}) for a full description): diff --git a/content/develop/clients/nodejs/error-handling.md b/content/develop/clients/nodejs/error-handling.md index 520f0781d4..0ed52b4fbf 100644 --- a/content/develop/clients/nodejs/error-handling.md +++ b/content/develop/clients/nodejs/error-handling.md @@ -92,7 +92,7 @@ below show how to implement these patterns in node-redis: ### Pattern 1: Fail fast -Catch specific errors and re-throw them (see +Catch specific errors that represent unrecoverable errors and re-throw them (see [Pattern 1: Fail fast]({{< relref "/develop/clients/error-handling#pattern-1-fail-fast" >}}) for a full description). diff --git a/content/develop/clients/redis-py/error-handling.md b/content/develop/clients/redis-py/error-handling.md index bd2103bed9..203d072bf5 100644 --- a/content/develop/clients/redis-py/error-handling.md +++ b/content/develop/clients/redis-py/error-handling.md @@ -2,7 +2,7 @@ title: Error handling description: Learn how to handle errors when using redis-py linkTitle: Error handling -weight: 50 +weight: 65 --- redis-py uses **exceptions** to signal errors. The redis-py documentation mainly @@ -53,7 +53,7 @@ redis-py: ### Pattern 1: Fail fast -Catch specific exceptions and re-raise them (see +Catch specific exceptions that represent unrecoverable errors and re-raise them (see [Pattern 1: Fail fast]({{< relref "/develop/clients/error-handling#pattern-1-fail-fast" >}}) for a full description): @@ -65,7 +65,7 @@ r = redis.Redis() try: result = r.get(key) except redis.ResponseError: - # This indicates a bug in our code + # This indicates a bug in the code raise ``` @@ -91,24 +91,12 @@ return database.get(key) Retry on temporary errors like timeouts (see [Pattern 3: Retry with backoff]({{< relref "/develop/clients/error-handling#pattern-3-retry-with-backoff" >}}) -for a full description): - -```python -import time - -max_retries = 3 -retry_delay = 0.1 - -for attempt in range(max_retries): - try: - return r.get(key) - except redis.TimeoutError: - if attempt < max_retries - 1: - time.sleep(retry_delay) - retry_delay *= 2 # Exponential backoff - else: - raise -``` +for a full description). redis-py has built-in retry logic +which is highly configurable. You can customize the retry strategy +(or supply your own custom strategy) and you can also specify which errors +should be retried. See +[Production usage]({{< relref "/develop/clients/redis-py/produsage#retries" >}}) +for more information. ### Pattern 4: Log and continue @@ -126,7 +114,8 @@ except redis.ConnectionError: ## Async error handling -If you're using `redis.asyncio`, error handling works the same way, but with `async`/`await`: +Error handling works the usual way when you use `async`/`await`, +as shown in the example below: ```python import redis.asyncio as redis @@ -142,22 +131,7 @@ async def get_with_fallback(key): await r.close() ``` -## Connection pool errors - -Connection pool exhaustion raises a `redis.ConnectionError`. Monitor pool usage -and adjust the pool size if necessary: - -```python -pool = redis.ConnectionPool( - host="localhost", - port=6379, - max_connections=50 # Adjust based on your needs -) -r = redis.Redis(connection_pool=pool) -``` - ## See also - [Error handling]({{< relref "/develop/clients/error-handling" >}}) - [Production usage]({{< relref "/develop/clients/redis-py/produsage" >}}) -- [Connection pooling]({{< relref "/develop/clients/pools-and-muxing" >}}) From 7d1d8eb588cb1e3e850bf78cb7af7d9a6a960661 Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Thu, 6 Nov 2025 14:23:19 +0000 Subject: [PATCH 16/16] DOC-5881 DOC-5885 added icons in error summary table --- content/develop/clients/go/error-handling.md | 8 ++++---- content/develop/clients/redis-py/error-handling.md | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/content/develop/clients/go/error-handling.md b/content/develop/clients/go/error-handling.md index 9032a5be7b..984becd2a8 100644 --- a/content/develop/clients/go/error-handling.md +++ b/content/develop/clients/go/error-handling.md @@ -29,10 +29,10 @@ Common error types from go-redis include: | Error | When it occurs | Recoverable | Recommended action | |---|---|---|---| -| `redis.Nil` | Key does not exist | Yes | Return default value or fetch from source | -| `context.DeadlineExceeded` | Operation timeout | Yes | Retry with backoff | -| `net.OpError` | Network error | Yes | Retry with backoff or fall back to alternative | -| `redis.ResponseError` | Redis error response | No | Fix the command or arguments | +| `redis.Nil` | Key does not exist | ✅ | Return default value or fetch from source | +| `context.DeadlineExceeded` | Operation timeout | ✅ | Retry with backoff | +| `net.OpError` | Network error | ✅ | Retry with backoff or fall back to alternative | +| `redis.ResponseError` | Redis error response | ❌ | Fix the command or arguments | See [Categories of errors]({{< relref "/develop/clients/error-handling#categories-of-errors" >}}) for a more detailed discussion of these errors and their causes. diff --git a/content/develop/clients/redis-py/error-handling.md b/content/develop/clients/redis-py/error-handling.md index 203d072bf5..52b85c1cde 100644 --- a/content/develop/clients/redis-py/error-handling.md +++ b/content/develop/clients/redis-py/error-handling.md @@ -40,10 +40,10 @@ for a more detailed discussion of these errors and their causes. | Exception | When it occurs | Recoverable | Recommended action | |---|---|---|---| -| `redis.ConnectionError` | Network or connection issues | Yes | Retry with backoff or fall back to alternative | -| `redis.TimeoutError` | Operation exceeded timeout | Yes | Retry with backoff | -| `redis.ResponseError` | Invalid command or Redis error response | No | Fix the command or arguments | -| `redis.DataError` | Data serialization/deserialization issues | Sometimes | Log, invalidate cache, fetch fresh data | +| `redis.ConnectionError` | Network or connection issues | ✅ | Retry with backoff or fall back to alternative | +| `redis.TimeoutError` | Operation exceeded timeout | ✅ | Retry with backoff | +| `redis.ResponseError` | Invalid command or Redis error response | ❌ | Fix the command or arguments | +| `redis.DataError` | Data serialization/deserialization issues | ⚠️ | Log, invalidate cache, fetch fresh data | ## Applying error handling patterns