{"record":{"id":"9736d8835287dd23","repo":"redis/go-redis","slug":"redis-can-t-parse-reply-100q-reading-string-int","errorCode":null,"errorMessage":"redis: can't parse reply=%.100q reading string into buffer","messagePattern":"redis: can't parse reply=%\\.100q reading string into buffer","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/proto/reader.go","lineNumber":664,"sourceCode":"\t\t// Slow path: buffer is exactly large enough for the payload only, so\n\t\t// read the payload into it and discard the CRLF separately.\n\t\tif _, err := io.ReadFull(r.rd, buf[:n]); err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\tif _, err := r.rd.Discard(2); err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\treturn n, nil\n\n\tcase RespInt, RespFloat:\n\t\ts := line[1:]\n\t\tif len(s) > len(buf) {\n\t\t\treturn 0, fmt.Errorf(\"redis: buffer too small: need %d bytes, have %d\", len(s), len(buf))\n\t\t}\n\t\treturn copy(buf, s), nil\n\t}\n\n\treturn 0, fmt.Errorf(\"redis: can't parse reply=%.100q reading string into buffer\", line)\n}\n\nfunc (r *Reader) ReadString() (string, error) {\n\tline, err := r.ReadLine()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tswitch line[0] {\n\tcase RespStatus, RespInt, RespFloat:\n\t\treturn string(line[1:]), nil\n\tcase RespString:\n\t\treturn r.readStringReply(line)\n\tcase RespBool:\n\t\tb, err := r.readBool(line)\n\t\treturn strconv.FormatBool(b), err\n\tcase RespVerbatim:\n\t\treturn r.readVerb(line)","sourceCodeStart":646,"sourceCodeEnd":682,"githubUrl":"https://github.com/redis/go-redis/blob/c5cad058c72f58370553b48566302303cf8a2e89/internal/proto/reader.go#L646-L682","documentation":"The reader received a reply line it could not interpret as a string when filling a caller-supplied buffer (ReadStringInto). After failing all known reply types (simple string, bulk string, verbatim, integer, etc.) it gives up and reports the raw line truncated to 100 chars. This almost always means the bytes on the wire are not a valid RESP reply for this position, or the reply type is one the parser does not support here.","triggerScenarios":"Calling ReadStringInto on a connection whose next reply is not a string-shaped RESP type (e.g. an array, map, nil, or unknown type byte), or when the line is corrupt/garbage from a protocol desync (e.g. after a partial read, a proxy injecting data, or talking to a non-Redis server).","commonSituations":"RESP proxies or load balancers mangling traffic; protocol desync after a previous command's reply was mis-consumed; pointing the client at a non-Redis service; RESP2 servers replying with types the caller didn't expect for custom commands.","solutions":["Ensure every issued command consumes exactly its reply — a desync from skipped replies makes subsequent reads parse garbage","Verify the endpoint is a real Redis server and no proxy rewrites responses","Use Protocol: 3 consistently if the server requires RESP3 types (maps/verbatim) your caller parses as strings","Log the %.100q payload in the error to identify the unexpected type byte"],"exampleFix":"// before: reading a custom command reply as a fixed-size string buffer\ncmd := NewStringCmd(ctx, \"MYCMD\")\nreader.ReadStringInto(buf)\n// after: parse according to the actual reply type\nval, err := reader.ReadString()\nif err != nil { return err }\ncopy(buf, val)","handlingStrategy":"type-guard","validationCode":"// ensure reply kind before reading into buffer\nline, err := r.PeekReplyType() // or read via ReadString first\nif err != nil { return err }\nif len(buf) < neededLen { return ErrBufferTooSmall }","typeGuard":"func isStringReply(t byte) bool {\n  return t == '+' || t == '$' || t == '=' || t == ':'\n}","tryCatchPattern":"n, err := reader.ReadStringInto(buf)\nvar perr *redis.ProtoError\nif errors.As(err, &perr) {\n  // bad reply type or too-small buffer: log perr and reset connection\n  _ = conn.Close()\n  return fmt.Errorf(\"string-into parse failed: %w\", err)\n}","preventionTips":["Always buffer-length check before ReadStringInto (need >= reply size)","Consume every reply of every command to keep the stream aligned","Match Protocol setting to server capability","Use redis-cli --raw to confirm reply shapes for custom commands"],"tags":["go-redis","resp-protocol","parsing","internal-proto"],"backgroundTag":"resp-reply-parse-failure","analyzedSha":"c5cad058c72f58370553b48566302303cf8a2e89","analyzedAt":"2026-09-01T06:50:53.388Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}