All Products
Search
Document Center

Tair (Redis® OSS-Compatible):Lua script syntax and solutions to common errors

Last Updated:Jul 09, 2025

Tair (Redis OSS-compatible) instances support Lua commands. Lua scripts can efficiently process compare-and-set (CAS) commands, improving instance performance and simplifying the implementation of features that were previously difficult or inefficient to implement. This topic describes the syntax and usage of Lua scripts.

Syntax

Click to view details

For more information about Redis commands, visit the Redis official website.

Command

Syntax

Description

EVAL

EVAL script numkeys [key [key ...]] [arg [arg ...]]

Executes a specified script that takes parameters and returns the output.

Parameters:

  • script: the Lua script.

  • numkeys: the number of arguments in the KEYS array. The number is a non-negative integer.

  • KEYS[]: the keys that you want to pass to the script as arguments.

  • ARGV[]: the additional arguments that you want to pass to the script. The indexes of the KEYS[] and ARGV[] parameters start from 1.

Note
  • The EVAL command loads a script into the script cache in a similar way as the SCRIPT LOAD command.

  • Mixed use or misuse of KEYS[] and ARGV[] may cause instances to run abnormally, especially in cluster mode. For more information, see Specific limits for cluster architecture.

  • We recommend that you pass values in the KEYS[] and ARGV[] parameters to call Lua scripts, instead of encoding parameters into Lua scripts. Otherwise, the memory usage of the Lua virtual machine increases and cannot be reduced at the earliest opportunity. In a worst-case scenario, an out of memory (OOM) error occurs on the instance and results in data loss.

EVALSHA

EVALSHA sha1 numkeys key [key ...] arg [arg ...]

Evaluates a cached script by its SHA1 digest and runs the script.

If the script is not cached in Tair (Redis OSS-compatible) when you use the EVALSHA command, Tair returns the NOSCRIPT error. Run the EVAL or SCRIPT LOAD command to cache the script in Tair and try again. For more information, see NOSCRIPT error.

SCRIPT LOAD

SCRIPT LOAD script

Caches a specified script and returns the SHA1 digest of the script.

SCRIPT EXISTS

SCRIPT EXISTS script [script ...]

Returns information about the existence of one or more scripts in the script cache by using their corresponding SHA1 digests. If a specified script exists, a value of 1 is returned. Otherwise, a value of 0 is returned.

SCRIPT KILL

SCRIPT KILL

Terminates a Lua script in execution.

SCRIPT FLUSH

SCRIPT FLUSH

Removes all Lua scripts from the script cache in the current instance.

The following sample code provides examples of specific Redis commands. Before the following commands are run, the SET foo value_test command is run.

  • Sample EVAL command:

    EVAL "return redis.call('GET', KEYS[1])" 1 foo

    Sample output:

    "value_test"
  • Sample SCRIPT LOAD command:

    SCRIPT LOAD "return redis.call('GET', KEYS[1])"

    Sample output:

    "620cd258c2c9c88c9d10db67812ccf663d96bdc6"
  • Sample EVALSHA command:

    EVALSHA 620cd258c2c9c88c9d10db67812ccf663d96bdc6 1 foo

    Sample output:

    "value_test"
  • Sample SCRIPT EXISTS command:

    SCRIPT EXISTS 620cd258c2c9c88c9d10db67812ccf663d96bdc6 ffffffffffffffffffffffffffffffffffffffff

    Sample output:

    1) (integer) 1
    2) (integer) 0
  • Sample SCRIPT FLUSH command:

    Warning

    This command deletes all cached Lua scripts from the instance. Make sure that you back up the Lua scripts before you run this command.

    SCRIPT FLUSH

    Sample output:

    OK

Performance optimization practices

Reduce memory and network overheads

When many scripts with duplicate functionality are cached in an instance, they consume a significant amount of memory and may even cause an out-of-memory (OOM) error. The following is an example of incorrect usage.

EVAL "return redis.call('set', 'k1', 'v1')" 0
EVAL "return redis.call('set', 'k2', 'v2')" 0

Solution:

  • Do not pass parameters to Lua scripts as constants to reduce memory usage.

    # The following commands serve the same purposes as the preceding sample commands but cache scripts only once.
    EVAL "return redis.call('set', KEYS[1], ARGV[1])" 1 k1 v1
    EVAL "return redis.call('set', KEYS[1], ARGV[1])" 1 k2 v2
  • Use the following command syntax to reduce memory and network overheads:

    SCRIPT LOAD "return redis.call('set', KEYS[1], ARGV[1])"    # After this command is run, Redis returns "55b22c0d0cedf3866879ce7c854970626dcef0c3"
    EVALSHA 55b22c0d0cedf3866879ce7c854970626dcef0c3 1 k1 v1
    EVALSHA 55b22c0d0cedf3866879ce7c854970626dcef0c3 1 k2 v2

Flush the Lua script cache

Used memory of an instance may be higher than expected because the Lua script cache takes up memory of the instance. When the used memory of the instance approaches or exceeds the upper limit, an OOM error is returned. Error example:

-OOM command not allowed when used memory > 'maxmemory'.

Solution:

Flush the Lua script cache by running the SCRIPT FLUSH command on the client. Different from the FLUSHALL command, the SCRIPT FLUSH command is synchronous. If the instance caches many Lua scripts, the SCRIPT FLUSH command can block the instance for an extended period of time and the involved instance may become unavailable. Proceed with caution. We recommend that you perform this operation during off-peak hours.

Note

If you click Clear Data in the console, data can be cleared but the Lua script cache cannot be flushed.

Do not write Lua scripts that may take up excessive amounts of memory. Moreover, do not write Lua scripts that involve large amounts of data. Otherwise, memory usage significantly increases and an OOM error may occur. To reduce memory usage, we recommend that you enable data eviction (enabled by default for instances, with volatile-lru mode). However, the instance does not evict the Lua script cache regardless of whether data eviction is enabled.

Error handling guide

NOSCRIPT error

If the script is not cached in the instance when you use the EVALSHA command, the instance returns the NOSCRIPT error. Error example:

(error) NOSCRIPT No matching script. Please use EVAL.

Solution:

Run the EVAL or SCRIPT LOAD command to cache the script in the instance and try again. In specific scenarios, such as instance migrations and configuration changes, the instance flushes the Lua script cache because the instance cannot ensure the persistence and replicability of Lua scripts. In this case, your client must be able to handle the error. For more information, see Persistence and replication issues.

The following sample Python code shows a method for handling the NOSCRIPT error. The sample code prepends strings by using Lua scripts.

Note

You can also use redis-py to handle this error. redis-py provides the Script class that encapsulates the judgment logic for Lua scripts of Redis, such as a catch statement for the NOSCRIPT error.

import redis
import hashlib

# strin is a string in Lua scripts. This function returns the sha1 value of strin in the string format.
def calcSha1(strin):
    sha1_obj = hashlib.sha1()
    sha1_obj.update(strin.encode('utf-8'))
    sha1_val = sha1_obj.hexdigest()
    return sha1_val

class MyRedis(redis.Redis):

    def __init__(self, host="localhost", port=6379, password=None, decode_responses=False):
        redis.Redis.__init__(self, host=host, port=port, password=password, decode_responses=decode_responses)

    def prepend_inLua(self, key, value):
        script_content = """\
        local suffix = redis.call("get", KEYS[1])
        local prefix = ARGV[1]
        local new_value = prefix..suffix
        return redis.call("set", KEYS[1], new_value)
        """
        script_sha1 = calcSha1(script_content)
        if self.script_exists(script_sha1)[0] == True:      # Check whether the script is already cached in Redis.
            return self.evalsha(script_sha1, 1, key, value) # If the script is already cached, the EVALSHA command is used to run the script.
        else:
            return self.eval(script_content, 1, key, value) # Otherwise, use the EVAL command to run the script. Note that the EVAL command can cache scripts in Redis. You can also use the SCRIPT LOAD and EVALSHA commands.

r = MyRedis(host="r-******.redis.rds.aliyuncs.com", password="***:***", port=6379, decode_responses=True)

print(r.prepend_inLua("k", "v"))
print(r.get("k"))
            

Lua script timeout error

  • Slow Lua requests may block the instance because a Lua script is atomically executed in the instance. One Lua script can block the instance for up to 5 seconds. After 5 seconds, the instance returns a BUSY error for other commands until the script execution is complete.

    BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE.

    Solution:

    Run the SCRIPT KILL command to terminate the Lua script or wait until the Lua script execution is complete.

    Note
    • During the first 5 seconds when a slow Lua script is being executed, the SCRIPT KILL command does not take effect because the instance is being blocked.

    • To prevent the instance from being blocked for an extended period of time, we recommend that you estimate the amount of time required to execute a Lua script when you write the Lua script, check for infinite loop, and split the Lua script if necessary.

  • If a Lua script has already run write commands against the dataset, the SCRIPT KILL command does not take effect. Error example:

    (error) UNKILLABLE Sorry the script already executed write commands against the dataset. You can either wait the script termination or kill the server in a hard way using the SHUTDOWN NOSAVE command.

    Solution:

    On the Instances page of the console, find the instance that you want to manage and click restart.

Persistence and replication issues

Tair (Redis OSS-compatible) keeps caching the Lua scripts that have been executed in an instance if the instance is not restarted or the SCRIPT FLUSH command is not run for the instance. However, Tair (Redis OSS-compatible) cannot ensure the persistence of Lua scripts or the synchronization of Lua scripts from the current node to other nodes in scenarios such as instance migrations, configuration changes, version upgrades, and instance switchovers.

Solution:

Store all Lua scripts in your on-premise device. Recache the Lua scripts in Tair (Redis OSS-compatible) by using the EVAL or SCRIPT LOAD command if necessary. This prevents a NOSCRIPT error from occurring when Lua scripts are cleared during an instance restart or a high availability (HA) switchover.

Special limits on cluster instances

Constraints of cluster architecture

  • To ensure execution atomicity, a Lua script cannot be split and can be executed only on one shard in a cluster instance. In most cases, a key is used to determine which shard Lua scripts are routed to. Therefore, you must specify at least one key when you run a Lua script in a cluster instance. If you want to read or write multiple keys, the keys in the one Lua script must belong to the same slot. Otherwise, an abnormal execution result is returned. Lua scripts that do not have keys (such as KEYS, SCAN, and FLUSHDB) can be executed normally. However, only the data of a single shard is returned. This limit is caused by the architecture of cluster instances.

  • When you run the SCRIPT LOAD command on one node, a Lua script may not be stored on other nodes.

Error codes in proxy mode

The proxy performs syntax checks to identify the keys that belong to multiple slots and throw exceptions in advance to assist troubleshooting. The proxy uses a check method different from that of the Lua virtual machine. This places additional limits on the execution of Lua scripts in proxy mode. For example, the UNPACK command is not supported, and the EVAL, EVALSHA, and SCRIPT commands are not supported in MULTI and EXEC transactions.

You can also set the script_check_enable parameter to disable additional checks on Lua syntax in proxy mode.

If the readonly_lua_route_ronode_enable parameter is set to 1 for a read/write splitting instance, proxy nodes check whether Lua scripts contain only read-only commands and determine whether to forward them to read-only nodes. This check logic imposes limits on Lua syntax.

Note

How does setting the script_check_enable parameter to 0 affect the instance?

  • If the instance is compatible with Redis 5.0 (with minor version earlier than 5.0.8) and 4.0 or earlier, we recommend that you do not disable the checks. Otherwise, normal results may be returned when the script is not executed normally.

  • If you disable the checks on other versions, the proxy no longer checks Lua syntax, but data nodes still check Lua syntax.

The following describes the error codes and causes.

Limits of Redis Cluster architecture

  • Error code: -ERR for redis cluster, eval/evalsha number of keys can't be negative or zero\r\n

    Description: You must include a key when you execute a Lua script. Proxy nodes use the key to determine the shard to which the Lua script is forwarded.

    # Example of valid usage
    EVAL "return redis.call('get', KEYS[1])" 1 fooeval
    
    # Example of invalid usage
    EVAL "return redis.call('get', 'foo')" 0
  • Error code: -ERR 'xxx' command keys must in same slot

    Description: Multiple keys in a Lua script must belong to the same slot.

    # Example of valid usage:
    EVAL "return redis.call('mget', KEYS[1], KEYS[2])" 2 foo {foo}bar
    
    # Example of invalid usage:
    EVAL "return redis.call('mget', KEYS[1], KEYS[2])" 2 foo foobar

Additional limits caused by Lua syntax checks in proxy mode

Note

You can disable the script_check_enable parameter to prevent the proxy from performing additional checks on Lua syntax.

  • Error code: -ERR bad lua script for redis cluster, nested redis.call/redis.pcall

    Description: Nested calls are not supported. You can call the Lua script by using local variables.

    # Example of valid usage
    EVAL "local value = redis.call('GET', KEYS[1]); redis.call('SET', KEYS[2], value)" 2 foo bar
    
    # Example of invalid usage
    EVAL "redis.call('SET', KEYS[1], redis.call('GET', KEYS[2]))" 2 foo bar
  • Error code: -ERR bad lua script for redis cluster, first parameter of redis.call/pcall must be a single literal string

    Description: The command called in redis.call/pcall must be a string literal.

    # Example of valid usage
    eval "redis.call('GET', KEYS[1])" 1 foo
    
    # Example of invalid usage
    eval "local cmd = 'GET'; redis.call(cmd, KEYS[1])" 1 foo

Limitations in specific versions (only for Redis Open-Source Edition 5.0 with a minor version earlier than 5.0.8, instances of version 4.0 or earlier, proxy versions for cloud-native editions earlier than 7.0.2, or proxy versions for classic editions earlier than 6.8.12)

Note
  • The following limitations apply only to Redis Open-Source Edition instances that run Redis 5.0 (with a minor version earlier than 5.0.8) or Redis 4.0 or earlier, or instances with an earlier proxy version (cloud-native edition earlier than 7.0.2 or classic edition earlier than 6.8.12).

  • In most cases, you can ignore the following content if the instance version and proxy version are higher than the preceding versions. However, if the limits still exist when the instance version is higher than the preceding versions, modify any proxy parameter such as query_cache_expire. Wait for 1 minute and try again.

  • Error code:-ERR bad lua script for redis cluster, all the keys that the script uses should be passed using the KEYS array\r\n

    For commands called within redis.call or redis.pcall, all keys must be passed from the KEYS array and cannot be Lua variables.

    # Example of valid command usage:
    EVAL "return redis.call('mget', KEYS[1], KEYS[2])" 2 foo {foo}bar
    
    # Example of invalid command usage:
    EVAL "return redis.call('mget', KEYS[1], '{foo}bar')" 1 foo                      # This command is invalid because the '{foo}bar' key must be specified by using the KEYS array.
    EVAL "local i = 2 return redis.call('mget', KEYS[1], KEYS[i])" 2 foo {foo}bar    # This command is invalid because the index of keys consists of variables, which is not allowed for an instance in proxy mode. Instances in direct connection mode are not subject to this limit.
    EVAL "return redis.call('mget', KEYS[1], ARGV[1])" 1 foo {foo}bar                # This command is invalid because ARGV[1] cannot be specified as a key.
  • Error code: -ERR bad lua script for redis cluster, all the keys that the script uses should be passed using the KEYS array, include destination, and KEYS should not be in expression

    Description: The destination parameter of the ZUNIONSTORE and ZINTERSTORE commands must be specified by using the KEYS array.

  • Error code: -ERR bad lua script for redis cluster, ZUNIONSTORE/ZINTERSTORE numkeys parameter should be a single number and not expression

    Description: The numkeys parameter of the ZUNIONSTORE and ZINTERSTORE commands is not a constant.

  • Error code: -ERR bad lua script for redis cluster, ZUNIONSTORE/ZINTERSTORE numkeys value is not an integer or out of range

    Description: The numkeys parameter of the ZUNIONSTORE and ZINTERSTORE commands is not a number.

  • Error code: -ERR bad lua script for redis cluster, ZUNIONSTORE/ZINTERSTORE all the keys that the script uses should be passed using the KEYS array

    Description: All keys of the ZUNIONSTORE and ZINTERSTORE commands must be specified by using the KEYS array.

  • Error code: -ERR bad lua script for redis cluster, XREAD/XREADGROUP all the keys that the script uses should be passed using the KEYS array

    Description: All keys of the XREAD and XREADGROUP commands must be specified by using the KEYS array.

  • Error code: -ERR bad lua script for redis cluster, all the keys that the script uses should be passed using the KEYS array, and KEYS should not be in expression, sort command store key does not meet the requirements

    Description: The keys of the SORT commands must be specified by using the KEYS array.

Read/write permission issues

  • Error code: -ERR Write commands are not allowed from read-only scripts

    Description: Lua scripts sent by using the EVAL_RO command cannot contain write commands.

  • Error code: -ERR bad write command in no write privilege

    Description: Lua scripts sent by a read-only account cannot contain write commands.

Unsupported commands

Lua syntax errors

  • Error code: -ERR bad lua script for redis cluster, redis.call/pcall expect '(' or -ERR bad lua script for redis cluster, redis.call/redis.pcall definition is not complete, expect ')'

    Description: Lua syntax error. The redis.call function must be followed by the complete set of ( and ).

  • Error code: -ERR bad lua script for redis cluster, at least 1 input key is needed for ZUNIONSTORE/ZINTERSTORE

    Description: The numkeys parameter of the ZUNIONSTORE and ZINTERSTORE commands must be greater than 0.

  • Error code: -ERR bad lua script for redis cluster, ZUNIONSTORE/ZINTERSTORE key count < numkeys

    Description: The number of keys in the ZUNIONSTORE and ZINTERSTORE commands is less than the numkeys value.

  • Error code: -ERR bad lua script for redis cluster, xread/xreadgroup command syntax error

    Description: The XREAD or XREADGROUP command uses incorrect syntax. Check the number of parameters.

  • Error code: -ERR bad lua script for redis cluster, xread/xreadgroup command syntax error, streams must be specified

    Description: The streams parameter is required in the XREAD and XREADGROUP commands.

  • Error code: -ERR bad lua script for redis cluster, sort command syntax error

    Description: The SORT command uses incorrect syntax.

FAQ

  • Q: Does DMS support the execution of Lua scripts?

    A: Commands related to Lua scripts are not currently supported in the DMS console. You can use a client or redis-cli to connect to instances and use Lua scripts.