mirror of
https://github.com/kvcache-ai/Mooncake.git
synced 2026-11-05 01:17:55 +00:00
[GH-ISSUE #4099] [Bug]: RedisStoragePlugin set()/remove() report REDIS_REPLY_ERROR as success #1039
Labels
No labels
ascend
auto-closed
bug
bug
CI/Build
Common
documentation
enhancement
feature request
good first issue
help wanted
high priority
MetaX
nightly-failure
pull-request
PyTorch Backend
question
RFC
Roadmap
stale
Store
Tests
Transfer Engine
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
kvcache-ai/Mooncake#1039
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @zuozhubinge on GitHub (Sep 14, 2026).
Original GitHub issue: https://github.com/kvcache-ai/Mooncake/issues/4099
Environment
RedisStoragePluginis built (-DUSE_REDIS=ON)mainDescription
RedisStoragePlugin::set()andRedisStoragePlugin::remove()inmooncake-transfer-engine/src/transfer_metadata_plugin.cpptreat any non-null reply assuccess. They never inspect
reply->type, so aREDIS_REPLY_ERROR— an error reply theserver deliberately sent — is reported to the caller as a completed write:
The consequence is a silent write loss.
registerSegmentDesc()andunregisterSegmentDesc()see success, log nothing, and continue, while Redis holds nonew value. Remote peers then resolve a stale descriptor or none at all, and there is no
signal anywhere that the publish did not happen.
The most likely trigger is a failover. When a managed Redis promotes a replica, or a
load balancer briefly routes to one, the connection is healthy and the command is
rejected with
-READONLY:redisCommand()returns a valid reply object in that case, so nothing in the currentcode path notices. Other realistic cases are
-OOMundermaxmemory,-MISCONFwhenRDB persistence is failing, and
-NOAUTHif a reconnect lands on a server that requirescredentials the client does not have.
get()is affected differently but not silently: an error reply has a non-nullstr, soit is passed to the JSON parser and surfaces as a misleading
RedisStoragePlugin: JSON parse errorrather than as a backend error.Expected Behavior
A
REDIS_REPLY_ERRORshould be reported as failure, with the server's error string inthe log so
-READONLYis distinguishable from a connection problem.set()andremove()should return false, andgetWithStatus()should map it tokUnavailablerather than letting it reach the JSON parser.
Retrying is deliberately not the answer: the server answered, so the command was
received and rejected. Only the reporting is wrong.
Steps to Reproduce
Point a node at a Redis replica, or set
maxmemorylow enough to force-OOM, andregister a segment:
registerSegmentDesc()returns success and logs nothing, but the key is absent fromRedis.
Additional Context
Raised as a follow-up from the review of #4042, which fixed the connection-recovery half
of #4003 and left this reporting gap untouched to keep that diff focused. #4042 makes the
failover case slightly more reachable, since a reconnect can now land on a different
server than the original connection did.
I am happy to take this one.
@github-actions[bot] commented on GitHub (Sep 14, 2026):
Thanks for opening this issue, @zuozhubinge!
13146499A maintainer will triage this when possible. To help us respond faster, please include:
Useful links: Documentation · Contributing guide
@he-yufeng commented on GitHub (Sep 14, 2026):
Fix up at #4107. Verified the report against current main and reproduced the silent-write path end to end: with a fake Redis answering -READONLY to every command, the stock class reports set()/remove() as success, and with the patch both fail loudly with the server's error string in the log. The healthy path (writes succeed, nil GET still maps to kNotFound) is unchanged.
One adjustment to the expected-behavior sketch: getWithStatus() on an error reply does land on kUnavailable today, but only by falling out of the JSON parser with a misleading log line. The PR makes that path explicit.