Skip to content

[BUG] Breaking Change to error handling in MULTI blocks #1629

Open
@MightySepp666

Description

@MightySepp666

Describe the bug

During my tests of migrating from Redis (more precisely KeyDB) to Valkey, I found an undocumented change to the handling of errors within a MULTI block, which prevents Valkey to be used as a drop-in replacement. While there is a documentation about transactions in the Valkey Readme, I couldn't find any information about this change (and it took me days of debugging).

Behavior in Redis (and KeyDB): commands within a MULTI block are executed, even if there are errors in the chain
Behavior in Valkey: all commands are aborted, as soon as there is one error in the chain.

Please note, that personally, I am absolutely in favor of failing fast. So for me this behavior is much more desirable than before, because it pointed me to an error in our application logic. It's up to you to decide, whether you want this behavior only to apply with the strong compatibility mode.

But please at least mention this breaking change in the docs, as it would have saved me (and maybe others) days of searching and debugging.

To reproduce

  • run a current Valkey image: docker run -it --rm --detach 'valkey/valkey:8.0.2-alpine3.21'
  • note the ID of the started container
  • connect to the started container: docker exec -it <id-of-container> /bin/sh
  • connect via CLI: valkey-cli
  • run these commands:
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> SET test-key test-value
QUEUED
127.0.0.1:6379(TX)> WATCH test-key
(error) ERR Command not allowed inside a transaction
127.0.0.1:6379(TX)> EXEC
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> GET test-key
(nil)

=> the test-key was not stored

Expected behavior

In order to be used as a drop-in replacement, the valid commands should have been executed, like demonstrated here:

  • run a Redis 7 image: docker run -it --rm --detach 'valkey/valkey:8.0.2-alpine3.21'
  • note the ID of the started container
  • connect to the started container: docker exec -it <id-of-container> /bin/sh
  • connect via CLI: redis-cli
  • run these commands:
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> SET test-key test-value
QUEUED
127.0.0.1:6379(TX)> WATCH test-key
(error) ERR WATCH inside MULTI is not allowed
127.0.0.1:6379(TX)> EXEC
1) OK
127.0.0.1:6379> GET test-key
"test-value"

Additional information

In our application, we don't make use of the CLI, but use a client library instead (for PHP). This client library didn't report the error back to the caller, effectively hiding the error from the developer. So as I said, failing hard in this case would be an acceptable behavior for me - maybe controllable by a flag.

The only issue I could find, that lead me into the right direction is this one (though it's of a different project): taskforcesh/bullmq#2787.

Also worth mentioning is, that the error message in Valkey is not as meaningful as the one in Redis, which usually complicates finding and resolving errors.

Metadata

Metadata

Assignees

No one assigned

    Labels

    major-decision-pendingMajor decision pending by TSC teamnot-a-bugNothing wrong, nothing to fix

    Type

    No type

    Projects

    Status

    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions