Skip to content

[BUG] Inconsistency in errors returned from EVAL scripts. #10165

Description

@yoav-steinberg

When running a LUA script via eval we may get an Redis error response (a RESP error line starting with -) for different reasons:

  1. We executed a Redis command with redis.call() which returned an error.
  2. We returned a result of a call redis.pcall() which itself returned an error.
  3. We failed to execute a command via redis.call() because of some state (for example write command with EVAL_RO during OOM condition).
  4. We returned a result of failed attempt to execute a command via redis.pcall() because of some state (for example write command with EVAL_RO during OOM condition).

Each of these returns the error differently and in cases 3,4 above the format seems a bit arbitrary based on what type of error state was encountered.

Details:

 1: config set maxmemory 1
 2: +OK
 3: eval "return redis.call('set','x','y')" 0
 4: -ERR Error running script (call to 71e6319f97b0fe8bdfa1c5df3ce4489946dda479): @user_script:1: @user_script: 1: -OOM command not allowed when used memory > 'maxmemory'.
 5: eval "return redis.pcall('set','x','y')" 0
 6: -@user_script: 1: -OOM command not allowed when used memory > 'maxmemory'.
 7: eval "return redis.call('select',99)" 0
 8: -ERR Error running script (call to 4ad5abfc50bbccb484223905f9a16f09cd043ba8): @user_script:1: ERR DB index is out of range
 9: eval "return redis.pcall('select',99)" 0
10: -ERR DB index is out of range
11: eval_ro "return redis.call('set','x','y')" 0
12: -ERR Error running script (call to 71e6319f97b0fe8bdfa1c5df3ce4489946dda479): @user_script:1: @user_script: 1: Write commands are not allowed from read-only scripts.
13: eval_ro "return redis.pcall('set','x','y')" 0
14: -@user_script: 1: Write commands are not allowed from read-only scripts.

Issues:

  • In line 4 (and 12) redis.call() failed because of pre-existing state (OOM/ro). Script execution is aborted with generic error (-ERR Error runnning script) wrapping the internal error (-OOM...). The wrapper includes a "stack trace" (@user_script:1). The internal error is also wrapped in a stack trace (this time with a space before the line number @user_script: 1). We should avoid the double stack trace.

  • In line 4 the internal error is formatted like a valid Redis error response (-OOM), but in line 12 we have a similar call that fails before of attempting to call a WRITE command from eval_ro. This time the internal error is just a string with error code or status marker (Write commands are not...). This is inconsistent.

  • In line 6 we return the error object we received from a failed redis.pcall() because of an OOM state. This isn't prefixed with any error code, which seems very unorthodox and should be fixed.

  • In line 8 we abort the script with an error because of an error in the command executed by a redis.call() (select 99). The error is wrapped generically with a "stack trace" and seems fine but this time the wrapped error's leading - was trimmed becoming inconsistent with line 4.

In addition to this here:

redis/src/script_lua.c

Lines 447 to 454 in 857dc5b

if(lua_getstack(lua, 1, &dbg) && lua_getinfo(lua, "nSl", &dbg)) {
sds msg = sdscatprintf(sdsempty(), "%s: %d: %s",
dbg.source, dbg.currentline, error);
lua_pushstring(lua, msg);
sdsfree(msg);
} else {
lua_pushstring(lua, error);
}

There's code (which in practice never executes) which returns the error string unwrapped by the "stack trace" if it fails to get it. In such a case we might return a double "-" sign or prepend the "-" sign to some random text like -Write commands are not allowed....

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions