{"record":{"id":"d82917e8073c49a4","repo":"redis/go-redis","slug":"invalid-key-type-at-index-d","errorCode":null,"errorMessage":"invalid key type at index %d","messagePattern":"invalid key type at index (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"search_commands.go","lineNumber":3044,"sourceCode":"\nfunc (cmd *FTHybridCmd) RawVal() interface{} {\n\tcmd.await()\n\treturn cmd.rawVal\n}\n\nfunc (cmd *FTHybridCmd) RawResult() (interface{}, error) {\n\tcmd.await()\n\treturn cmd.rawVal, cmd.err\n}\n\nfunc parseFTHybrid(data []interface{}, withCursor bool) (FTHybridResult, *FTHybridCursorResult, error) {\n\t// Convert to map\n\tresultMap := make(map[string]interface{})\n\tfor i := 0; i < len(data); i += 2 {\n\t\tif i+1 < len(data) {\n\t\t\tkey, ok := data[i].(string)\n\t\t\tif !ok {\n\t\t\t\treturn FTHybridResult{}, nil, fmt.Errorf(\"invalid key type at index %d\", i)\n\t\t\t}\n\t\t\tresultMap[key] = data[i+1]\n\t\t}\n\t}\n\n\t// Handle cursor result\n\tif withCursor {\n\t\tsearchCursorID, ok1 := resultMap[\"SEARCH\"].(int64)\n\t\tvsimCursorID, ok2 := resultMap[\"VSIM\"].(int64)\n\t\tif !ok1 || !ok2 {\n\t\t\treturn FTHybridResult{}, nil, fmt.Errorf(\"invalid cursor result format\")\n\t\t}\n\t\treturn FTHybridResult{}, &FTHybridCursorResult{\n\t\t\tSearchCursorID: int(searchCursorID),\n\t\t\tVsimCursorID:   int(vsimCursorID),\n\t\t}, nil\n\t}\n","sourceCodeStart":3026,"sourceCodeEnd":3062,"githubUrl":"https://github.com/redis/go-redis/blob/c5cad058c72f58370553b48566302303cf8a2e89/search_commands.go#L3026-L3062","documentation":"When parsing an FT.HYBRID flat key/value reply, the client walks the reply array two elements at a time and expects each even-index element to be a string field name. If data[i] is not a string, the reply structure is not what the parser understands, so it fails with the offending index. This indicates the server returned a malformed or unexpected FT.HYBRID reply layout.","triggerScenarios":"Calling FTHybrid with the flat array parser path when the server reply contains non-string keys at even positions — e.g. a server version emitting different field names, or a RESP2 vs RESP3 reply-shape mismatch being fed to the wrong parser.","commonSituations":"Running against a Redis stack version whose FT.HYBRID reply layout differs from what this go-redis version expects; using a proxy that converts maps to arrays with binary keys; mock tests returning mis-shaped arrays.","solutions":["Verify server/RediSearch version matches the go-redis version's expected FT.HYBRID reply format (upgrade go-redis or the server so both agree)","Check protocol negotiation: use Protocol: 3 so the RESP3 map path is taken instead of the flat-array path","Inspect the reply at the reported index with a ProcessHook or MONITOR to see what the server actually returned","Fix mocks/tests to emit string keys at even indices in flat arrays"],"exampleFix":"// before (test mock)\n[]interface{}{int64(1), \"results\"}\n// after\n[]interface{}{\"total_results\", int64(1), \"results\", []interface{}{}}","handlingStrategy":"type-guard","validationCode":"// pre-check server capabilities before enabling hybrid search\nif err := rdb.Do(ctx, \"FT.INFO\", \"idx\").Err(); err != nil { /* index/server does not support expected format */ }","typeGuard":"func isStringKeyedFlatPairs(data []interface{}) bool {\n    if len(data)%2 != 0 { return false }\n    for i := 0; i < len(data); i += 2 {\n        if _, ok := data[i].(string); !ok { return false }\n    }\n    return true\n}","tryCatchPattern":"res, err := rdb.FTHybrid(ctx, \"idx\", query, opts).Result()\nif err != nil {\n    if strings.Contains(err.Error(), \"invalid key type\") {\n        // log raw reply via hook, flag server/proxy incompatibility\n    }\n    return err\n}","preventionTips":["Keep client and server versions aligned","Use Protocol: 3 so the map parsing path is used","Validate test fixtures against the documented FT.HYBRID reply format"],"tags":["redis","search","resp-protocol","deserialization"],"backgroundTag":"unexpected-response-shape","analyzedSha":"c5cad058c72f58370553b48566302303cf8a2e89","analyzedAt":"2026-09-01T06:50:53.388Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}