{"id":"109c4e73cbfc8a2b","repo":"go-redis/redis","slug":"redis-expected-but-got-line-q","errorCode":null,"errorMessage":"redis: expected '*', but got line %q","messagePattern":"redis: expected '\\*', but got line %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"redis.go","lineNumber":1889,"sourceCode":"\t\t\t}\n\t\t}\n\t}\n\n\t// To be sure there are no buffered push notifications, we process them before reading the reply\n\tif err := c.processPendingPushNotificationWithReader(ctx, cn, rd); err != nil {\n\t\tinternal.Logger.Printf(ctx, \"push: error processing pending notifications before reading reply: %v\", err)\n\t}\n\t// Parse number of replies.\n\tline, err := rd.ReadLine()\n\tif err != nil {\n\t\tif err == Nil {\n\t\t\terr = TxFailedErr\n\t\t}\n\t\treturn err\n\t}\n\n\tif line[0] != proto.RespArray {\n\t\treturn fmt.Errorf(\"redis: expected '*', but got line %q\", line)\n\t}\n\n\treturn nil\n}\n\n//------------------------------------------------------------------------------\n\n// Client is a Redis client representing a pool of zero or more underlying connections.\n// It's safe for concurrent use by multiple goroutines.\n//\n// Client creates and frees connections automatically; it also maintains a free pool\n// of idle connections. You can control the pool size with Config.PoolSize option.\ntype Client struct {\n\t*baseClient\n\tcmdable\n\n\t// cscLifecycleOwner keeps the canonical Client wrapper (the one whose GC\n\t// cleanup owns the drainer) reachable while a WithTimeout clone can still","sourceCodeStart":1871,"sourceCodeEnd":1907,"githubUrl":"https://github.com/go-redis/redis/blob/36d97525cd8076aed67cddf54778e9ea84550929/redis.go#L1871-L1907","documentation":"Thrown by txPipelineReadQueued after MULTI sends QUEUED acknowledgements for every command: the next line from the server must be a RESP array ('*<n>') giving the number of replies. If the first byte is not '*' (e.g. an inline error, a push frame leaking through, or protocol desync), the pipeline transaction is considered corrupt and the error is returned.","triggerScenarios":"Calling a MULTI/EXEC transaction (TxPipeline, Watch transaction, or any tx-pipelined path) against a server or proxy that does not return the standard RESP array count after QUEUED, or after a connection state where a non-array reply appears mid-transaction.","commonSituations":"A RESP-incompatible proxy or LSW/APT redis surrogate injected an inline reply; protocol desync caused by an earlier malformed command; an upstream that injects a status/error line instead of the array count; a corrupt TCP stream or TLS middlebox; a server-side OUT-OF-MEMORY or loading reply mid-EXEC.","solutions":["Check the %q line value in the error — it tells you exactly what the server sent instead of '*'; an error string points at a server-side rejection.","If a proxy is in the path, bypass it and retry against the real Redis to isolate proxy protocol bugs.","Ensure the server is not in LOADING state or out-of-memory during the EXEC; both can produce non-array replies.","Reproduce with redis-cli MULTI/EXEC to confirm the server emits the expected array count."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// There is no caller-side input that prevents a protocol desync;\n// instead validate the server is RESP-compliant before transacting.\nif err := probeClient.Ping(ctx).Err(); err != nil {\n    return fmt.Errorf(\"server not healthy for transactions: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"err := client.Watch(ctx, func(tx *redis.Tx) error { ... }, key)\nif err != nil && strings.Contains(err.Error(), \"expected '*'\") {\n    // protocol desync: reconnect and retry once; if it recurs, report server/proxy bug\n}","preventionTips":["Do not place non-Redis-compatible proxies in front of transactional workloads.","Avoid MULTI/EXEC while the server is in LOADING state or out of memory.","Capture the %q line from the error in logs — it is the single most useful diagnostic."],"tags":["protocol","transaction","pipeline","resp"],"analyzedSha":"36d97525cd8076aed67cddf54778e9ea84550929","analyzedAt":"2026-08-06T01:08:27.376Z","schemaVersion":2}