{"id":"1a3deac99ee33d8d","repo":"go-redis/redis","slug":"redis-got-d-elements-in-the-xmessage-array-expe","errorCode":null,"errorMessage":"redis: got %d elements in the XMessage array, expected 2 or 4","messagePattern":"redis: got (.+?) elements in the XMessage array, expected 2 or 4","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"command.go","lineNumber":2822,"sourceCode":"\n\tmsgs := make([]XMessage, n)\n\tfor i := 0; i < len(msgs); i++ {\n\t\tif msgs[i], err = readXMessage(rd); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn msgs, nil\n}\n\nfunc readXMessage(rd *proto.Reader) (XMessage, error) {\n\t// Read array length can be 2 or 4 (with CLAIM metadata)\n\tn, err := rd.ReadArrayLen()\n\tif err != nil {\n\t\treturn XMessage{}, err\n\t}\n\n\tif n != 2 && n != 4 {\n\t\treturn XMessage{}, fmt.Errorf(\"redis: got %d elements in the XMessage array, expected 2 or 4\", n)\n\t}\n\n\tid, err := rd.ReadString()\n\tif err != nil {\n\t\treturn XMessage{}, err\n\t}\n\n\tv, err := stringInterfaceMapParser(rd)\n\tif err != nil {\n\t\tif err != proto.Nil {\n\t\t\treturn XMessage{}, err\n\t\t}\n\t}\n\n\tmsg := XMessage{\n\t\tID:     id,\n\t\tValues: v,\n\t}","sourceCodeStart":2804,"sourceCodeEnd":2840,"githubUrl":"https://github.com/go-redis/redis/blob/36d97525cd8076aed67cddf54778e9ea84550929/command.go#L2804-L2840","documentation":"Returned by readXMessage (command.go:2822), used by every stream-read path (XREAD/XREADGROUP/XCLAIM/XAUTOCLAIM). Each XMessage is encoded as an array whose length is either 2 (id + field-values) or 4 (id + field-values + claim metadata: millis-since-delivery + delivered-count, from XAUTOCLAIM/XCLAIM). Any other length yields this error rather than reading garbage fields.","triggerScenarios":"Reading from a stream where the server returns an XMessage array with a length other than 2 or 4 — e.g. a future Redis adding more claim fields, a proxy rewriting the frame, or stream-data corruption.","commonSituations":"Upgrading the client but not the server (or vice-versa) across a version that changed XCLAIM/XAUTOCLAIM reply shape; a RESP proxy corrupting array framing; a Redis fork/fork-patched build with different stream reply semantics.","solutions":["Pin client and server to compatible Redis versions (XCLAIM metadata shape is version-dependent).","If on a fork/patched Redis, switch to upstream or implement a custom parser via Do().","Capture a RESP trace to confirm whether the server or a proxy is producing the unexpected length, then file a bug against the offender."],"exampleFix":"// before\nmsgs, err := rdb.XRead(ctx, &redis.XReadArgs{Streams: []string{\"s\", \"0\"}}).Result()\n// err: got N elements in the XMessage array, expected 2 or 4\n\n// after — pin a compatible server, or fall back to raw parsing\nraw, err := rdb.Do(ctx, \"XREAD\", \"STREAMS\", \"s\", \"0\").Result()\n// type-switch on raw and decode manually","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"msgs, err := rdb.XRead(ctx, args).Result()\nif err != nil && strings.Contains(err.Error(), \"XMessage array, expected 2 or 4\") {\n    // unexpected stream reply shape — pin client/server versions or decode raw\n}","preventionTips":["Keep client and server Redis versions aligned across XCLAIM/XAUTOCLAIM changes.","Avoid RESP-mangling proxies for stream workloads.","On shape errors, capture a RESP trace before reporting."],"tags":["command","reply-parsing","streams","xclaim","protocol-mismatch"],"analyzedSha":"36d97525cd8076aed67cddf54778e9ea84550929","analyzedAt":"2026-08-06T01:08:27.376Z","schemaVersion":2}