Skip to content

fix(storages): propagate Redis errors in RedisStorage save/load/clear - #4385

Open
icn5381 wants to merge 1 commit into
camel-ai:masterfrom
icn5381:fix/4383-redis-storage-error-handling
Open

icn5381 wants to merge 1 commit into
camel-ai:masterfrom
icn5381:fix/4383-redis-storage-error-handling

Conversation

@icn5381

@icn5381 icn5381 commented Oct 1, 2026

Copy link
Copy Markdown

Description

RedisStorage.save(), load() and clear() (and their async helpers) wrapped every call in a blanket try/except that only logged the error. As a result:

  • save() returned None whether or not the write reached Redis, so a failed save looked like a successful one.
  • load() returned [] when Redis was unreachable, which is indistinguishable from an empty session.

An agent using RedisStorage for chat history could lose everything to a Redis outage and carry on with no memory and no error.

This lets the three methods raise the underlying error, matching InMemoryKeyValueStorage and JsonStorage, the other BaseKeyValueStorage implementations. load() still returns [] when nothing has been stored for the session, so the empty-session behavior is unchanged.

Changes

  • Removed the swallowing try/except blocks from save(), load(), clear(), _async_save(), _async_load() and _async_clear() in camel/storages/key_value_storages/redis.py.
  • Documented the Raises behavior in the docstrings and dropped the now-unused logger.
  • Added regression tests covering error propagation for all three methods, the ValueError path for an uninitialized client, and the unchanged empty-session load() result.

Testing

pytest test/storages/key_value_storages/test_redis.py -v — 8 passed (3 existing + 5 new).

Fixes #4383

RedisStorage wrapped save(), load() and clear() (and their async
helpers) in blanket try/except blocks that only logged the error.
save() returned None whether or not the write reached Redis, and
load() returned [] for an unreachable server, which is
indistinguishable from an empty session. An agent could silently
lose its history to a Redis outage and carry on with no memory.

Let the three methods raise, matching InMemoryKeyValueStorage and
JsonStorage, the other BaseKeyValueStorage implementations.
load() still returns [] when nothing is stored for the session.

Fixes camel-ai#4383
@coderabbitai

coderabbitai Bot commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Advanced

Run ID: c1ec011c-763b-4c53-9c2a-60a6c0398ed6

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chrikrah chrikrah left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@icn5381, on the code I would merge this, and one repository requirement is still open, which the last paragraph is about. The behaviour you describe reaches a caller of ChatHistoryMemory, and the falsification holds at d59c4a2 against the merge base 0106b76:

$ PYTHONPATH=<exported camel tree> python memory_path.py
# memory_path.py, in full: RedisStorage(sid="probe", loop=asyncio.new_event_loop()) built with
#   RedisStorage._create_client patched out, then storage._client = a MagicMock whose .get and .set
#   are AsyncMock(side_effect=ConnectionError("Error 111 connecting to localhost:6379")), wrapped in
#   ChatHistoryMemory(ScoreBasedContextCreator(OpenAITokenCounter(ModelType.GPT_4O_MINI), 4096)).
# 0106b76
ERROR camel.storages.key_value_storages.redis - Error loading records: Error 111 connecting to localhost:6379
memory.retrieve()      -> []
memory.get_context()   -> ([], 0)
# d59c4a2
memory.retrieve()      -> raised ConnectionError: Error 111 connecting to localhost:6379
memory.get_context()   -> raised ConnectionError: Error 111 connecting to localhost:6379
$ pytest test/storages/key_value_storages/test_redis.py -q    # exported tree, PYTHONPATH=<tree>
# 0106b76                                 3 passed
# d59c4a2                                 8 passed
# d59c4a2 tests, redis.py from 0106b76    4 failed, 4 passed
#   test_save_propagates_error, test_load_propagates_error, test_clear_propagates_error,
#   test_methods_without_client_raise
# ruff 0.7.4, the .pre-commit-config.yaml pin: All checks passed, 2 files already formatted
# not run: test_mem0_cloud.py in the same directory, 14 failures on 0106b76 and on d59c4a2 alike,
#          from the missing mem0 package here

non-blocking: Mem0Storage swallows the same way at camel/storages/key_value_storages/mem0_cloud.py:136, :180 and :218, and the description names only InMemoryKeyValueStorage and JsonStorage as the other implementations.

@fengju0213, you closed #4242 on redis.py under the AI-Generated Code Policy, which asks for an accepted issue first, and the linked #4383 has no maintainer response on it yet. Would you accept #4383? That reads to me as the gate on this one rather than anything in the diff.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] RedisStorage.save() reports success when the write failed, and load() returns [] for an unreachable Redis

2 participants