{"record":{"id":"a6df9e22fd248980","repo":"thanos-io/thanos","slug":"mset-the-length-of-keys-and-values-not-equal-len","errorCode":null,"errorMessage":"MSet the length of keys and values not equal, len(keys)=%d, len(values)=%d","messagePattern":"MSet the length of keys and values not equal, len\\(keys\\)=(.+?), len\\(values\\)=(.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/cortex/chunk/cache/redis_client.go","lineNumber":114,"sourceCode":"\tpingResp, err := resp.ToString()\n\tif err != nil {\n\t\treturn errors.New(\"converting PING response to string\")\n\t}\n\tif pingResp != \"PONG\" {\n\t\treturn errors.Errorf(\"redis: Unexpected PING response %q\", pingResp)\n\t}\n\treturn nil\n}\n\nfunc (c *RedisClient) MSet(ctx context.Context, keys []string, values [][]byte) error {\n\tvar cancel context.CancelFunc\n\tif c.timeout > 0 {\n\t\tctx, cancel = context.WithTimeout(ctx, c.timeout)\n\t\tdefer cancel()\n\t}\n\n\tif len(keys) != len(values) {\n\t\treturn errors.Errorf(\"MSet the length of keys and values not equal, len(keys)=%d, len(values)=%d\", len(keys), len(values))\n\t}\n\n\tcmds := make(rueidis.Commands, 0, len(keys))\n\tfor i := range keys {\n\t\tcmds = append(cmds, c.rdb.B().Set().Key(keys[i]).Value(rueidis.BinaryString(values[i])).Ex(c.expiration).Build())\n\t}\n\tfor _, resp := range c.rdb.DoMulti(ctx, cmds...) {\n\t\tif err := resp.Error(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (c *RedisClient) MGet(ctx context.Context, keys []string) ([][]byte, error) {\n\tvar cancel context.CancelFunc\n\tif c.timeout > 0 {\n\t\tctx, cancel = context.WithTimeout(ctx, c.timeout)","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/internal/cortex/chunk/cache/redis_client.go#L96-L132","documentation":"RedisClient.MSet pipelines one SET command per key and requires the keys and values slices to be parallel arrays of equal length. If the lengths differ it returns immediately with this error rather than silently storing a partial batch.","triggerScenarios":"Calling MSet(ctx, keys, values) where len(keys) != len(values) — e.g. a caller builds keys from one list and values from a filtered/truncated list.","commonSituations":"Batching code that drops failed entries from values but not keys; off-by-one slicing; passing decoded results of unequal length from upstream parsing.","solutions":["Fix the caller to construct keys and values together so they stay index-aligned.","Add an assertion in the batching loop that both slices grow in lockstep.","If values may be missing, append nil placeholders to keep lengths equal before calling MSet.","Read the len(keys)/len(values) numbers in the message to find which side is short and by how much."],"exampleFix":"// before\nvalues := results[:maxBatch] // can shorten values only\nclient.MSet(ctx, keys, values)\n// after\nif len(values) > len(keys) { values = values[:len(keys)] }\nif len(keys) > len(values) { keys = keys[:len(values)] }\nclient.MSet(ctx, keys, values)","handlingStrategy":"validation","validationCode":"if len(keys) != len(values) {\n    return fmt.Errorf(\"MSet pre-check: len(keys)=%d len(values)=%d\", len(keys), len(values))\n}","typeGuard":null,"tryCatchPattern":"if err := client.MSet(ctx, keys, values); err != nil {\n    if strings.Contains(err.Error(), \"length of keys and values not equal\") {\n        log.Errorf(\"batching bug: keys=%d values=%d\", len(keys), len(values))\n    }\n    return err\n}","preventionTips":["Build keys and values pairs in one loop, never in separate passes.","Deduplicate/trim both slices together before batching.","Unit-test batch construction with filtered input."],"tags":["redis","arguments","batching"],"backgroundTag":"invalid-argument-value","analyzedSha":"35b8b991177def87ed52dcf10f9b6d87f07282c8","analyzedAt":"2026-09-07T01:49:59.689Z","contentChangedAt":"2026-09-07T01:49:59.689Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}