redis执行lua脚本报错90%以上是变量作用域或语法不兼容问题:未加local导致全局变量污染、keys/argv下标误用0起始、nil参数直传redis.call()、使用lua 5.2+语法(如table.unpack、goto、字符串插值)等。

Redis执行Lua脚本报解释器错误,90%以上是变量作用域写错或语法不兼容——不是脚本逻辑问题,而是Lua在Redis环境里的“方言”没写对。
KEYS/ARGV索引从1开始,但local变量漏写local会污染全局
Redis的Lua解释器(基于5.1)严格区分局部/全局变量,且KEYS和ARGV数组下标从1起算,不是0。常见错误:
- 写
KEYS[0]或ARGV[0]→ 报(error) ERR Error running script ... index out of bounds - 用
a = "test"定义变量却没加local→ 变成全局变量,后续脚本可能被覆盖或触发不可预测行为 - 混用
local key = KEYS[1]和redis.call("get", key)看似合理,但若KEYS[1]为空或为nil,redis.call()会直接报错而非返回nil
redis.call()和redis.pcall()对nil参数的处理差异极大
很多脚本崩溃是因为把未校验的KEYS[1]或ARGV[1]直接传给redis.call(),而它不接受nil作为命令参数:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
-
redis.call("get", nil)→ 立即抛出(error) ERR Error compiling script ... attempt to concatenate a nil value -
redis.pcall("get", nil)→ 返回{err="ERR wrong number of arguments for 'get' command"},不会中断脚本 - 正确做法:先判断
if KEYS[1] ~= nil then ... end,或统一用redis.pcall()捕获再处理
Redis Lua不支持标准Lua 5.2+语法,必须降级写法
Redis至今只支持Lua 5.1解释器(2.6–7.x全系),以下语法在本地Lua 5.3跑得通,但在Redis里直接报编译错误:
-
table.unpack()→ Redis中不存在,改用unpack()(5.1原生函数) -
goto语句 → 完全不识别,报syntax error near 'goto' -
local function f() ... end嵌套声明 → 部分版本解析失败,建议拆成local f = function() ... end - 字符串插值
"key_#{KEYS[1]}"→ 不支持,必须写成"key_"..KEYS[1]
SCRIPT LOAD后EVALSHA失败,常因客户端与服务端脚本缓存不一致
用SCRIPT LOAD预加载脚本后,拿到SHA1再调EVALSHA,却报NOSCRIPT,原因往往不是脚本内容不同,而是:
- 脚本末尾多了空格、换行或BOM头 → SHA1完全不同
- 客户端代码里拼接了
"\n"或System.lineSeparator(),而Redis服务端用的是Unix换行符 - Spring Data Redis等封装库自动trim脚本字符串,但
SCRIPT LOAD命令本身不trim → 导致两次计算SHA1不一致 - 集群模式下,脚本只加载到某个节点,但
EVALSHA路由到了其他节点 → 必须确保所有节点都执行过SCRIPT LOAD,或改用EVAL
最隐蔽的坑是:Redis Lua解释器不会告诉你“变量未定义”,只会报“attempt to index a nil value”,而这个nil可能来自KEYS[1]为空、redis.call()失败返回nil、或local漏写导致变量被当成全局但从未赋值——查的时候得一层层print(用redis.log(redis.LOG_WARNING, "debug: "..tostring(x)))才能定位真凶。










