Skip to content

Commit 89cfafd

Browse files
DOC-5881 first draft of error handling page
1 parent 33f6d61 commit 89cfafd

File tree

1 file changed

+357
-0
lines changed

1 file changed

+357
-0
lines changed
Lines changed: 357 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,357 @@
1+
---
2+
title: Error handling
3+
description: Learn how to handle errors when using Redis client libraries
4+
linkTitle: Error handling
5+
weight: 50
6+
---
7+
8+
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.
9+
10+
## Categories of errors
11+
12+
### Connection errors
13+
14+
Connection errors occur when your application cannot communicate with Redis. These are typically temporary and often recoverable.
15+
16+
**Common causes:**
17+
- Network connectivity issues
18+
- Redis server is down or unreachable
19+
- Authentication failure
20+
- Connection timeout
21+
- Connection pool exhaustion
22+
23+
**Examples:**
24+
- `ConnectionError`: Network failure or server unreachable
25+
- `TimeoutError`: Operation exceeded the configured timeout
26+
- `AuthenticationError`: Invalid credentials
27+
28+
**When to handle:** Almost always. Connection errors are usually temporary, so implementing retry logic or fallback strategies is recommended.
29+
30+
**Example strategy:**
31+
32+
```mermaid {width="100%"}
33+
graph TB
34+
A["Try to connect<br/>to Redis"]
35+
A -->|Success| B(["Use the result"])
36+
A -->|Failure| C{Error type?}
37+
C -->|Timeout| D(["Retry with<br/>exponential backoff"])
38+
C -->|Auth failure| E(["Check credentials<br/>and fail"])
39+
C -->|Network error| F(["Fallback to<br/>alternative data source"])
40+
```
41+
42+
### Command errors
43+
44+
Command errors occur when Redis receives an invalid or malformed command. These typically indicate a bug in your code.
45+
46+
**Common causes:**
47+
- Typo in command name
48+
- Wrong number of arguments
49+
- Invalid argument types
50+
- Using a command that doesn't exist in your Redis version
51+
52+
**Examples:**
53+
- `ResponseError`: Invalid command or syntax error
54+
- `WRONGTYPE Operation against a key holding the wrong kind of value`
55+
- `ERR unknown command`
56+
57+
**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.
58+
59+
**Example:**
60+
61+
```mermaid {width="60%"}
62+
graph TB
63+
A["User provides<br/>JSONPath expression"]
64+
A --> B["Try to execute it"]
65+
direction TB
66+
B -->|ResponseError| C["Log the error"]
67+
C --> D(["Return default value<br/>or error message to user"])
68+
B -->|Success| E(["Use the result"])
69+
```
70+
71+
### Data errors
72+
73+
Data errors occur when there's a problem with the data itself—serialization failures, corrupted data, or type mismatches.
74+
75+
**Common causes:**
76+
- Object cannot be serialized to JSON
77+
- Cached data is corrupted
78+
- Attempting to deserialize invalid data
79+
- Type mismatch (e.g., trying to use string operations on a list)
80+
81+
**Examples:**
82+
- `JSONDecodeError`: Cannot deserialize JSON data
83+
- `SerializationError`: Cannot serialize object
84+
- `WRONGTYPE`: Operating on wrong data type
85+
86+
**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.
87+
88+
**Example:**
89+
90+
```mermaid {width="60%"}
91+
graph TB
92+
A["Read cached data"]
93+
A --> B["Try to deserialize"]
94+
B -->|Success| C(["Use the data"])
95+
B -->|Deserialization fails| D["Log the error"]
96+
D --> E["Delete corrupted<br/>cache entry"]
97+
E --> F(["Fetch fresh data<br/>from source"])
98+
```
99+
100+
### Resource errors
101+
102+
Resource errors occur when Redis runs out of resources or hits limits.
103+
104+
**Common causes:**
105+
- Memory limit reached
106+
- Connection pool exhausted
107+
- Too many connections
108+
- Key eviction due to memory pressure
109+
110+
**Examples:**
111+
- `OOM command not allowed when used memory > 'maxmemory'`
112+
- Connection pool timeout
113+
- `LOADING Redis is loading the dataset in memory`
114+
115+
**When to handle:** Sometimes. Some resource errors are temporary (Redis loading), while others indicate a configuration problem.
116+
117+
**Example:**
118+
119+
```mermaid {width="80%"}
120+
graph TB
121+
A{Resource error<br/>occurred?}
122+
A -->|Redis loading| B(["Retry after<br/>a delay"])
123+
A -->|Memory full| C(["Check Redis<br/>configuration and data"])
124+
A -->|Pool exhausted| D(["Increase pool size<br/>or reduce concurrency"])
125+
```
126+
127+
## Error handling patterns
128+
129+
### Pattern 1: Fail fast
130+
131+
Use this when the error is unrecoverable or indicates a bug in your code.
132+
133+
**When to use:**
134+
- Command errors (invalid syntax)
135+
- Authentication errors
136+
- Programming errors
137+
138+
**Example:**
139+
```python
140+
try:
141+
result = r.get(key)
142+
except redis.ResponseError as e:
143+
# This indicates a bug in our code
144+
raise # Re-raise the exception
145+
```
146+
147+
### Pattern 2: Graceful degradation
148+
149+
Use this when you have an alternative way to get the data.
150+
151+
**When to use:**
152+
- Cache reads (fallback to database)
153+
- Session reads (fallback to default values)
154+
- Optional data (skip if unavailable)
155+
156+
**Example:**
157+
```python
158+
try:
159+
cached_value = r.get(key)
160+
if cached_value:
161+
return cached_value
162+
except redis.ConnectionError:
163+
logger.warning("Cache unavailable, using database")
164+
165+
# Fallback to database
166+
return database.get(key)
167+
```
168+
169+
### Pattern 3: Retry with backoff
170+
171+
Use this when the error is temporary and the operation is idempotent.
172+
173+
**When to use:**
174+
- Connection timeouts
175+
- Temporary network issues
176+
- Redis loading data
177+
178+
**Example:**
179+
```python
180+
import time
181+
182+
max_retries = 3
183+
retry_delay = 0.1
184+
185+
for attempt in range(max_retries):
186+
try:
187+
return r.get(key)
188+
except redis.TimeoutError:
189+
if attempt < max_retries - 1:
190+
time.sleep(retry_delay)
191+
retry_delay *= 2 # Exponential backoff
192+
else:
193+
raise
194+
```
195+
196+
### Pattern 4: Log and continue
197+
198+
Use this when the operation is not critical to your application.
199+
200+
**When to use:**
201+
- Cache writes (data loss is acceptable)
202+
- Non-critical updates
203+
- Metrics collection
204+
205+
**Example:**
206+
```python
207+
try:
208+
r.setex(key, 3600, value)
209+
except redis.ConnectionError:
210+
logger.warning(f"Failed to cache {key}, continuing without cache")
211+
# Application continues normally
212+
```
213+
214+
## Decision tree: How to handle errors
215+
216+
```mermaid
217+
graph LR
218+
Start{Error occurred?}
219+
220+
Start -->|Connection error| C1{Operation type?}
221+
C1 -->|Read| C2["Graceful degradation<br/>fallback"]
222+
C1 -->|Write| C3["Log and continue<br/>or retry"]
223+
C1 -->|Critical| C4["Retry with backoff"]
224+
225+
Start -->|Command error| Cmd1{Error source?}
226+
Cmd1 -->|User input| Cmd2["Log and return<br/>error to user"]
227+
Cmd1 -->|Your code| Cmd3["Fail fast<br/>fix the bug"]
228+
229+
Start -->|Data error| D1{Operation type?}
230+
D1 -->|Read| D2["Log, invalidate,<br/>fallback"]
231+
D1 -->|Write| D3["Log and fail<br/>data is invalid"]
232+
233+
Start -->|Resource error| R1{Error type?}
234+
R1 -->|Redis loading| R2["Retry with backoff"]
235+
R1 -->|Pool exhausted| R3["Increase pool size"]
236+
R1 -->|Memory full| R4["Check configuration"]
237+
```
238+
239+
## Logging and monitoring
240+
241+
### What to log
242+
243+
- **Error type and message:** What went wrong?
244+
- **Context:** Which key? Which operation?
245+
- **Timestamp:** When did it happen?
246+
- **Retry information:** Is this a retry? How many attempts?
247+
248+
**Example:**
249+
```python
250+
logger.error(
251+
"Redis operation failed",
252+
extra={
253+
"error_type": type(e).__name__,
254+
"operation": "get",
255+
"key": key,
256+
"attempt": attempt,
257+
"timestamp": datetime.now().isoformat(),
258+
}
259+
)
260+
```
261+
262+
### What to monitor
263+
264+
- **Error rate:** How many errors per minute?
265+
- **Error types:** Which errors are most common?
266+
- **Recovery success:** How many retries succeed?
267+
- **Fallback usage:** How often do we use fallback strategies?
268+
269+
These metrics help you identify patterns and potential issues.
270+
271+
## Common mistakes
272+
273+
### ❌ Catching all exceptions
274+
275+
```python
276+
try:
277+
result = r.get(key)
278+
except Exception: # Too broad!
279+
pass
280+
```
281+
282+
**Problem:** You might catch unexpected errors and hide bugs.
283+
284+
**✅ Better:**
285+
```python
286+
try:
287+
result = r.get(key)
288+
except redis.ConnectionError:
289+
# Handle connection error
290+
pass
291+
```
292+
293+
### ❌ Not distinguishing error types
294+
295+
```python
296+
try:
297+
result = r.get(key)
298+
except redis.ResponseError:
299+
# Retry? This won't help if it's a syntax error!
300+
retry()
301+
```
302+
303+
**Problem:** Different errors need different handling.
304+
305+
**✅ Better:**
306+
```python
307+
try:
308+
result = r.get(key)
309+
except redis.TimeoutError:
310+
retry() # Retry on timeout
311+
except redis.ResponseError:
312+
raise # Fail on syntax error
313+
```
314+
315+
### ❌ Retrying non-idempotent operations
316+
317+
```python
318+
# This increments the counter each retry!
319+
for attempt in range(3):
320+
try:
321+
r.incr(counter)
322+
break
323+
except redis.TimeoutError:
324+
pass # Retry
325+
```
326+
327+
**Problem:** Retrying non-idempotent operations can cause data corruption.
328+
329+
**✅ Better:** Only retry idempotent operations (GET, SET with same value) or use transactions.
330+
331+
### ❌ Ignoring connection pool errors
332+
333+
```python
334+
# Pool is exhausted, but we don't handle it
335+
result = r.get(key) # Might timeout waiting for connection
336+
```
337+
338+
**Problem:** Connection pool errors indicate a configuration or concurrency issue.
339+
340+
**✅ Better:** Monitor pool usage and increase size if needed.
341+
342+
## Client-specific error handling
343+
344+
For detailed information about exceptions in your client library, see:
345+
346+
- [redis-py error handling]({{< relref "/develop/clients/redis-py/error-handling" >}})
347+
- [Node.js error handling]({{< relref "/develop/clients/nodejs/error-handling" >}})
348+
- [Java (Jedis) error handling]({{< relref "/develop/clients/jedis/error-handling" >}})
349+
- [Go (go-redis) error handling]({{< relref "/develop/clients/go/error-handling" >}})
350+
- [.NET (NRedisStack) error handling]({{< relref "/develop/clients/dotnet/error-handling" >}})
351+
352+
## Next steps
353+
354+
- Learn about [connection pooling]({{< relref "/develop/clients/pools-and-muxing" >}}) to avoid resource errors
355+
- Explore [client-side caching]({{< relref "/develop/clients/client-side-caching" >}}) for resilient applications
356+
- See [use-case guides]({{< relref "/develop/use-cases" >}}) for pattern-specific error handling examples
357+

0 commit comments

Comments
 (0)