All Products
Search
Document Center

Tair (Redis® OSS-Compatible):Lua script specifications and common errors

Last Updated:Jun 26, 2026

Tair (Redis OSS-compatible) instances support Lua commands. You can use Lua scripts to efficiently handle compare-and-set (CAS) operations, improve instance performance, and implement patterns that are otherwise difficult or inefficient to achieve. This topic describes the basic syntax and usage guidelines for Lua scripts.

Basic syntax

Show 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 script with the specified parameters and returns the result.

Parameters:

  • script: The Lua script.

  • numkeys: A non-negative integer that specifies the number of key arguments in the KEYS[] array.

  • KEYS[]: The Redis key arguments passed to the script.

  • ARGV[]: The script arguments passed to the script. The indexes for both KEYS[] and ARGV[] start from 1.

Note
  • Like the SCRIPT LOAD command, the EVAL command caches the Lua script on the instance.

  • Improper use of KEYS[] and ARGV[] can lead to unexpected behavior, especially in cluster mode. For more information, see Special restrictions in 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 ...]

Executes a script by its SHA1 digest.

If you run the EVALSHA command and the script corresponding to the sha1 value is not cached in Redis, Redis returns a NOSCRIPT error. To resolve this, use the EVAL or SCRIPT LOAD command to cache the script, and then retry. For more information, see NOSCRIPT error.

SCRIPT LOAD

SCRIPT LOAD script

Caches the given script on the instance and returns its SHA1 digest.

SCRIPT EXISTS

SCRIPT EXISTS script [script ...]

Checks whether one or more scripts, identified by their SHA1 digests, exist in the instance's script cache. It returns 1 for each script that exists and 0 for each script that does not.

SCRIPT KILL

SCRIPT KILL

Stops a running Lua script.

SCRIPT FLUSH

SCRIPT FLUSH

Clears all Lua scripts from the current instance's script cache.

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

Optimize memory and network overhead

Caching a large number of functionally repetitive scripts consumes significant memory and can even trigger 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:

  • To reduce memory waste, avoid hardcoding arguments as constants within the Lua script.

    # Achieves the same functionality as the incorrect example but only caches the script 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
  • For greater efficiency, we recommend the following approach to reduce both memory usage and network overhead.

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

Clear Lua script memory

The Lua script cache consumes instance memory, contributing to the used_memory metric. If the instance's memory usage approaches or exceeds maxmemory, it can trigger an out of memory (OOM) error. An example error is shown below:

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

Solution:

Execute the SCRIPT FLUSH command from a client to clear the Lua script cache. The recommended method depends on your instance version:

  • Asynchronous cleanup (Recommended): open source Redis 7.0 or later and Tair (Enterprise Edition) 6.0 or later support the SCRIPT FLUSH ASYNC command. This command clears the Lua script cache in the background without blocking the instance, minimizing the impact on your services.

    SCRIPT FLUSH ASYNC
  • Synchronous cleanup: For earlier versions, the SCRIPT FLUSH command operates synchronously. If the instance has a large number of cached Lua scripts, this command can block the instance for an extended period and may make it unavailable. Use this command with caution, preferably during off-peak hours.

    SCRIPT FLUSH
Note

Clicking Purge Data in the console only clears data and does not clear the Lua script cache.

In addition, avoid writing excessively large Lua scripts to prevent high memory consumption. Do not perform bulk data writes within a Lua script, as this can cause a sharp increase in memory usage and may lead to an OOM error. If your business logic allows, we recommend enabling data eviction (enabled by default with the volatile-lru policy) to save memory space. However, the instance does not evict the Lua script cache, regardless of whether data eviction is enabled.

Error handling

NOSCRIPT error

When you use the EVALSHA command, if the script corresponding to the sha1 value is not cached on the instance, the instance returns a NOSCRIPT error. An example is shown below:

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

Solution:

Use the EVAL or SCRIPT LOAD command to cache the script on the instance, and then retry. However, the instance does not guarantee the persistence or replication of Lua scripts. In some scenarios, such as an instance migration or a configuration change, the Lua script cache may be cleared. Therefore, your client application must be able to handle this error. For more information, see Persistence and replication issues.

The following Python demo shows an example of how to handle a NOSCRIPT error. This demo uses a Lua script to perform a string prepend operation.

Note

You can also use the redis-py library for Python to handle this type of error. The library provides a Script class that encapsulates low-level logic for Redis Lua scripting, such as catching NOSCRIPT errors.

import redis
import hashlib

# This function takes a Lua script as a string and returns its SHA1 digest.
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]:      # Check if the script is cached in Redis.
            return self.evalsha(script_sha1, 1, key, value) # If cached, run the script with EVALSHA.
        else:
            return self.eval(script_content, 1, key, value) # Otherwise, run the script with EVAL, which also caches it. Alternatively, you could use SCRIPT LOAD and then EVALSHA.

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 errors

  • Because Lua scripts execute atomically, a slow-running script can block the instance. If a script runs for more than 5 seconds, the instance returns a BUSY error for all other commands until the script finishes executing.

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

    Solution:

    You can use the SCRIPT KILL command to terminate the Lua script or wait for it to complete.

    Note
    • The SCRIPT KILL command does not take effect during the first 5 seconds of a slow script's execution because the instance is blocked.

    • When writing Lua scripts, estimate their execution time and check for issues like infinite loops. This helps prevent long-running scripts from blocking the instance and making the service unavailable. If necessary, break down long scripts into smaller ones.

  • If the current Lua script has already executed a write command, the SCRIPT KILL command will not work. An example error is shown below:

    (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:

    In the console, go to the Instances page and click restart for the corresponding instance.

Persistence and replication issues

The instance caches executed Lua scripts indefinitely unless it is restarted or the SCRIPT FLUSH command is called. However, in certain situations, such as an instance migration, a configuration change, a version upgrade, or an HA switchover, the instance does not guarantee the persistence of Lua scripts or their replication to other nodes.

Solution:

Because the instance does not guarantee script persistence or replication, you should store all Lua scripts locally. When necessary, use the EVAL or SCRIPT LOAD command to recache the scripts on the instance. This prevents NOSCRIPT errors that can occur if the script cache is cleared during operations like an instance restart or an HA switchover.

Special restrictions in cluster architecture

Cluster architecture constraints

  • To ensure atomicity, a Lua script cannot be split and must be executed on a single shard in a cluster architecture. The instance typically uses a key to determine which shard to route the command to. Therefore, you must specify at least one key when you execute a Lua script in a cluster. If a script accesses multiple keys, they must all belong to the same slot; otherwise, the script will fail or return incorrect results. Commands without keys, such as KEYS, SCAN, and FLUSHDB, can run but will only return data from a single shard. These limitations are inherent to the Redis Cluster architecture.

  • Running the SCRIPT LOAD command on a single node does not guarantee that the script is stored on other nodes.

Error codes in proxy mode

The proxy performs syntax checks to proactively identify cases where keys span multiple slots. This helps detect issues early for easier troubleshooting. The proxy's checking method differs from that of the Lua virtual machine, resulting in additional restrictions when executing Lua commands in proxy mode. For example, the UNPACK command is not supported, and EVAL, EVALSHA, and SCRIPT-series commands cannot be used within MULTI/EXEC transactions.

You can also disable some of the proxy's Lua syntax checks by turning off the script_check_enable parameter.

Additionally, for a read/write splitting instance, if the readonly_lua_route_ronode_enable parameter is enabled, the proxy checks if a Lua script contains only read-only commands to determine whether it can be forwarded to a read-only node. This check logic imposes limitations on Lua syntax.

Note

Disabling the script_check_enable parameter has the following effects:

  • For instances of open source Redis 5.0 (minor versions earlier than 5.0.8) or Redis 4.0 and earlier, we do not recommend disabling this parameter. Doing so may cause a script to return a success message even when it executes incorrectly.

  • For other versions, disabling this parameter stops the proxy from checking Lua syntax, but the data nodes will still perform their normal syntax checks.

The following are the specific error codes and their causes.

Redis Cluster architecture limitations

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

    Description: You must specify at least one key when executing a Lua script. The proxy uses the key to determine which shard to forward the script to.

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

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

    # Correct example:
    EVAL "return redis.call('mget', KEYS[1], KEYS[2])" 2 foo {foo}bar
    
    # Incorrect example:
    EVAL "return redis.call('mget', KEYS[1], KEYS[2])" 2 foo foobar

Proxy Lua syntax restrictions

Note

You can avoid the proxy's additional Lua syntax checks by disabling the script_check_enable parameter.

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

    Description: Nested Redis calls are not supported. Use local variables as an alternative.

    # Correct example
    EVAL "local value = redis.call('GET', KEYS[1]); redis.call('SET', KEYS[2], value)" 2 foo bar
    
    # Incorrect example
    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/redis.pcall must be a single literal string

    Description: The command invoked within redis.call/pcall must be a string literal.

    # Correct example
    eval "redis.call('GET', KEYS[1])" 1 foo
    
    # Incorrect example
    eval "local cmd = 'GET'; redis.call(cmd, KEYS[1])" 1 foo

Restrictions in specific versions (applies only to open source Redis 5.0 with minor versions earlier than 5.0.8, Redis 4.0 and earlier, cloud-native edition with proxy versions earlier than 7.0.2, and classic edition with proxy versions earlier than 6.8.12)

Note
  • The following restrictions apply only to open source Redis 5.0 (minor versions earlier than 5.0.8), Redis 4.0 and earlier, or instances with older proxy versions (cloud-native edition earlier than 7.0.2 or classic edition earlier than 6.8.12).

  • Typically, if your instance and proxy versions are higher than those listed, you can ignore the following content. However, if your instance is a higher version but still exhibits these restrictions, modify any proxy parameter (such as query_cache_expire), wait for 1 minute, and then retry.

  • 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

    Description: All keys must be passed through the KEYS array. For commands within redis.call/pcall, key positions must use the KEYS array, and you cannot substitute KEYS with a Lua variable.

    # Correct example:
    EVAL "return redis.call('mget', KEYS[1], KEYS[2])" 2 foo {foo}bar
    
    # Incorrect examples:
    EVAL "return redis.call('mget', KEYS[1], '{foo}bar')" 1 foo                      # The key '{foo}bar' should be passed through the KEYS array.
    EVAL "local i = 2 return redis.call('mget', KEYS[1], KEYS[i])" 2 foo {foo}bar    # This script is not allowed in proxy mode because the KEYS array index is a variable. This restriction does not exist in direct connection mode.
    EVAL "return redis.call('mget', KEYS[1], ARGV[1])" 1 foo {foo}bar                # An element from the ARGV array should not be used 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 passed 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 must be a constant, not an expression.

  • 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 for the ZUNIONSTORE and ZINTERSTORE commands must be passed 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 for the XREAD and XREADGROUP commands must be passed 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 key for the SORT command must be passed using the KEYS array.

Read/write permission issues

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

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

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

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

Unsupported commands

  • Error code: -ERR script debug not support

    Description: The proxy does not currently support the SCRIPT DEBUG command.

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

    Description: The Lua script contains a command that is not supported by the proxy. For more information, see Command restrictions on cluster and read/write splitting instances.

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 ')'

    Note: This is a Lua syntax error because the redis.call function must be followed by a complete pair of parentheses: ( 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 actual number of keys for the ZUNIONSTORE or ZINTERSTORE command is less than the specified numkeys value.

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

    Description: The syntax of the XREAD or XREADGROUP command is incorrect. 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 XREAD and XREADGROUP commands must include the streams parameter.

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

    Description: The syntax of the SORT command is incorrect.

FAQ

  • Q: Can I execute Lua scripts in Data Management (DMS)?

    A: The Data Management (DMS) console does not currently support Lua-related commands. To use Lua scripts, connect to your instance using a client or redis-cli.