How to fix ERR bad lua script for redis cluster, all the keys that the script uses should be passed using the KEYS array in Redis

RedisADVANCEDHIGHUpdated Dec 22, 2025· 223 views

This error occurs when a Lua script in Redis Cluster accesses keys without explicitly declaring them in the KEYS array. Redis Cluster requires all key names to be passed as input arguments for proper shard routing.

Quick fix

Fixes ERR bad lua script for redis cluster, all the keys that the script uses should be passed using the KEYS array

-- ❌ WRONG: Using Lua variable for key name
local key = "user:123"
redis.call('GET', key)

-- ❌ WRONG: String concatenation
redis.call('SET', 'user:' .. userId, value)

-- ❌ WRONG: Keys in expressions
local keys = {'key1', 'key2'}
redis.call('GET', keys[1])
  1. Identify how your script accesses keys
  2. Rewrite script to use KEYS array
  3. Update EVAL command to declare all keys
  4. Ensure multi-key scripts use hash tags
redis — error
-- ❌ WRONG: Using Lua variable for key name
local key = "user:123"
redis.call('GET', key)
-- ❌ WRONG: String concatenation
redis.call('SET', 'user:' .. userId, value)
-- ❌ WRONG: Keys in expressions
local keys = {'key1', 'key2'}
redis.call('GET', keys[1])
ERR bad lua script for redis cluster, all the keys that the script uses should be passed using the KEYS array

What this error means

This error is specific to Redis Cluster environments and occurs when a Lua script attempts to access Redis keys without properly declaring them through the KEYS array parameter. In Redis Cluster, data is distributed across multiple nodes based on key hash slots. Before executing a Lua script, Redis must determine which node should run the script by analyzing which keys it will access. When you use dynamic key names (Lua variables, string concatenation, or keys stored in data structures) instead of the KEYS array, Redis cannot perform this pre-execution analysis. The cluster doesn't know which node contains the required data, making it impossible to route the script correctly. This restriction is particularly strict in managed Redis services like Alibaba Cloud (Aliyun) Redis and AWS ElastiCache, where additional validation is enforced to prevent cross-slot errors and ensure cluster stability.

Typical symptoms

  • Lua scripts that work in standalone Redis fail when run on Redis Cluster
  • Error message mentions "KEYS array" when executing EVAL or EVALSHA commands
  • Scripts using redis.call() or redis.pcall() with dynamic key names fail
  • Rate limiting or atomic operation scripts break after migrating to cluster mode
  • Third-party libraries (Redisson, limiter, thunk-ratelimiter) throw cluster errors

Common causes

  1. Using Lua variables to construct key names instead of KEYS array (e.g., redis.call("GET", myvar))
  2. Accessing keys through string concatenation or Lua expressions in redis.call()
  3. Not passing key names as arguments when calling EVAL/EVALSHA commands
  4. Using keys stored in Redis data structures (lists, sets) without declaring them upfront
  5. Migrating scripts from standalone Redis to cluster without updating key access patterns
  6. Third-party libraries not designed for cluster compatibility

How to fix "ERR bad lua script for redis cluster, all the keys that the script uses should be passed using the KEYS array"

1Identify how your script accesses keys

Review your Lua script to find all redis.call() or redis.pcall() operations that access keys. Look for patterns like this:

lua
-- ❌ WRONG: Using Lua variable for key name
local key = "user:123"
redis.call('GET', key)

-- ❌ WRONG: String concatenation
redis.call('SET', 'user:' .. userId, value)

-- ❌ WRONG: Keys in expressions
local keys = {'key1', 'key2'}
redis.call('GET', keys[1])

The problem is that Redis Cluster cannot analyze these dynamic references before execution.

2Rewrite script to use KEYS array

Modify your Lua script to reference the KEYS array directly in all redis.call() operations:

lua
-- ✅ CORRECT: Using KEYS array
redis.call('GET', KEYS[1])
redis.call('SET', KEYS[2], ARGV[1])

-- ✅ CORRECT: Multiple keys from KEYS array
for i = 1, #KEYS do
  redis.call('DEL', KEYS[i])
end

Important rules:
- All key names must be accessed via KEYS[1], KEYS[2], etc.
- Use ARGV array for non-key arguments (values, flags, options)
- Never use Lua variables where KEYS should be used

3Update EVAL command to declare all keys

When calling EVAL or EVALSHA, you must specify the number of keys and pass them as arguments:

bash
# ❌ WRONG: No keys declared
EVAL "return redis.call('GET', 'user:123')" 0

# ✅ CORRECT: Declare 1 key
EVAL "return redis.call('GET', KEYS[1])" 1 user:123

# ✅ CORRECT: Multiple keys and arguments
EVAL "return redis.call('SET', KEYS[1], ARGV[1])" 1 user:123 "John"

In client libraries:

javascript
// Node.js ioredis
await redis.eval(
  "return redis.call('GET', KEYS[1])",
  1,              // number of keys
  'user:123'      // key name
);

// Python redis-py
redis.eval(
  "return redis.call('SET', KEYS[1], ARGV[1])",
  1,              # numkeys
  'user:123',     # key
  'value'         # argument
)
4Ensure multi-key scripts use hash tags

If your script accesses multiple keys, they must hash to the same slot. Use hash tags to guarantee this:

lua
-- ✅ CORRECT: Hash tags ensure same slot
redis.call('GET', KEYS[1])  -- {user:123}:profile
redis.call('GET', KEYS[2])  -- {user:123}:settings

When calling the script:

javascript
await redis.eval(
  script,
  2,
  '{user:123}:profile',    // Same hash tag {user:123}
  '{user:123}:settings'    // Same hash tag {user:123}
);

Redis hashes only the content inside curly braces, so both keys will be on the same cluster node.

5Test the updated script

Verify your script works in cluster mode:

bash
# Test with Redis CLI
redis-cli --cluster call <host>:6379 EVAL "return redis.call('GET', KEYS[1])" 1 testkey

# Check cluster slot assignment
redis-cli CLUSTER KEYSLOT testkey

In your application, add error handling:

javascript
try {
  const result = await redis.eval(script, numKeys, ...keys, ...args);
  console.log('Script executed successfully:', result);
} catch (error) {
  if (error.message.includes('bad lua script')) {
    console.error('Script still uses dynamic keys - review KEYS array usage');
  } else if (error.message.includes('CROSSSLOT')) {
    console.error('Keys are in different slots - use hash tags');
  }
  throw error;
}

Advanced notes

Alibaba Cloud (Aliyun) Redis Clusters:
Aliyun enforces stricter Lua script validation than standard Redis. Even scripts that might work on self-hosted clusters may fail. They provide a script_check_enable parameter you can set to 0 to disable validation, but this is not recommended as it can cause unpredictable behavior and data corruption.

KEYS vs ARGV semantics:
The KEYS array is special in Redis Cluster - it's used for slot calculation and routing. ARGV is for regular arguments (values, counters, flags). Mixing these up is a common mistake. If you're passing a key name, it belongs in KEYS, not ARGV.

Performance considerations:
Declaring keys explicitly has minimal overhead. Redis Cluster calculates hash slots using CRC16, which is extremely fast. The real benefit is preventing runtime errors and ensuring atomic operations stay on a single node.

Functions vs EVAL:
Redis 7.0+ introduced Redis Functions, which have similar KEYS requirements. When using FUNCTION LOAD, the same rules apply - use keys_function() to declare keys that will be passed in the KEYS array.

Cross-slot operations:
If you absolutely need to access keys across different slots, you cannot use Lua scripts atomically. Instead, use Redis Cluster's MULTI-EXEC with hash tags, or redesign your data model to co-locate related keys using consistent hash tags.

Frequently asked questions

What does "ERR bad lua script for redis cluster, all the keys that the script use" mean?
This error is specific to Redis Cluster environments and occurs when a Lua script attempts to access Redis keys without properly declaring them through the KEYS array parameter. In Redis Cluster, data is distributed across multiple nodes based on key hash slots. Before executing a Lua script, Redis must determine which node should run the script by analyzing which keys it will access.
How do I fix "ERR bad lua script for redis cluster, all the keys that the script use"?
This error occurs when a Lua script in Redis Cluster accesses keys without explicitly declaring them in the KEYS array. Redis Cluster requires all key names to be passed as input arguments for proper shard routing.
What causes "ERR bad lua script for redis cluster, all the keys that the script use"?
Using Lua variables to construct key names instead of KEYS array (e.g., redis.call("GET", myvar)) Accessing keys through string concatenation or Lua expressions in redis.call() Not passing key names as arguments when calling EVAL/EVALSHA commands
Is the "ERR bad lua script for redis cluster, all the keys that the script use" error serious?
Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.

Official resources & further reading