{"record":{"id":"1a8904c6019799bf","repo":"redis/go-redis","slug":"redis-function-stats-unexpected-s-engine-map-len","errorCode":null,"errorMessage":"redis: function stats unexpected %s engine map length","messagePattern":"redis: function stats unexpected (.+?) engine map length","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"command.go","lineNumber":7033,"sourceCode":"}\n\nfunc (cmd *FunctionStatsCmd) readEngines(rd *proto.Reader) ([]Engine, error) {\n\tn, err := rd.ReadMapLen()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tengines := make([]Engine, 0, n)\n\tfor i := 0; i < n; i++ {\n\t\tengine := Engine{}\n\t\tengine.Language, err = rd.ReadString()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\terr = rd.ReadFixedMapLen(2)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"redis: function stats unexpected %s engine map length\", engine.Language)\n\t\t}\n\n\t\tfor i := 0; i < 2; i++ {\n\t\t\tkey, err := rd.ReadString()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tswitch key {\n\t\t\tcase \"libraries_count\":\n\t\t\t\tengine.LibrariesCount, err = rd.ReadInt()\n\t\t\tcase \"functions_count\":\n\t\t\t\tengine.FunctionsCount, err = rd.ReadInt()\n\t\t\tdefault:\n\t\t\t\t// Unknown field: drain its value so the reader stays aligned\n\t\t\t\t// with the rest of the reply.\n\t\t\t\terr = rd.DiscardNext()\n\t\t\t}\n\t\t\tif err != nil {","sourceCodeStart":7015,"sourceCodeEnd":7051,"githubUrl":"https://github.com/redis/go-redis/blob/c5cad058c72f58370553b48566302303cf8a2e89/command.go#L7015-L7051","documentation":"While parsing FUNCTION STATS, each engine entry is expected to be a map of exactly 2 fields. If the engine map length is not 2, the client rejects the reply with this error. It guards against protocol changes in the FUNCTION STATS reply shape (e.g. new fields per engine) that the parser does not handle.","triggerScenarios":"Calling FunctionStats() when the server returns an engine object with more or fewer than 2 key/value pairs, at the ReadFixedMapLen(2) call in command.go:~7033.","commonSituations":"Redis server upgrade that added fields per engine in FUNCTION STATS; testing against Redis Edge/unstable builds; a RESP proxy that reshapes the reply.","solutions":["Upgrade go-redis to the latest release; newer parsers accept the extended engine map.","Verify REDIS_VERSION matches what your client supports (pin the server or the client accordingly).","If using a proxy that modifies FUNCTION STATS output, configure it to pass the reply through unchanged.","Report the discrepancy to redis/go-redis with the server version and reply if it persists."],"exampleFix":"// before: Redis 8.x engine map with 3 fields vs old client\nstats, err := rdb.FunctionStats(ctx)\n// redis: function stats unexpected lua engine map length\n\n// after: upgrade go-redis\n// go get github.com/redis/go-redis/v9@latest\nstats, err := rdb.FunctionStats(ctx)","handlingStrategy":"try-catch","validationCode":"// confirm reply shape first\nout, _ := rdb.Do(ctx, \"FUNCTION\", \"STATS\").Result()\nfmt.Printf(\"%#v\\n\", out) // inspect engine map arity","typeGuard":null,"tryCatchPattern":"stats, err := rdb.FunctionStats(ctx)\nif err != nil {\n    if strings.Contains(err.Error(), \"engine map length\") {\n        // use rdb.Do(ctx, \"FUNCTION\", \"STATS\") raw reply instead\n    }\n    return err\n}","preventionTips":["Upgrade go-redis before upgrading the Redis server","Avoid proxies that reshape module replies","Test FUNCTION STATS against your exact REDIS_VERSION in CI","Keep RESP3 enabled for richer reply structure"],"tags":["redis","function-stats","reply-parsing","protocol"],"backgroundTag":"unsupported-server-reply-format","analyzedSha":"c5cad058c72f58370553b48566302303cf8a2e89","analyzedAt":"2026-09-01T06:50:53.388Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}