{"record":{"id":"74955371615f57ce","repo":"redis/go-redis","slug":"ft-hybrid-vector-value-must-contain-a-blob-at-ind","errorCode":null,"errorMessage":"FT.HYBRID: vector Value must contain a blob at index 1","messagePattern":"FT\\.HYBRID: vector Value must contain a blob at index 1","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"search_commands.go","lineNumber":3804,"sourceCode":"\tswitch vector := v.(type) {\n\tcase *VectorFP32:\n\t\treturn hybridVectorBytes(vector.Val)\n\tcase *VectorFloat16:\n\t\treturn hybridVectorBytes(vector.Val)\n\tcase *VectorBFloat16:\n\t\treturn hybridVectorBytes(vector.Val)\n\tcase *VectorFloat64:\n\t\treturn hybridVectorBytes(vector.Val)\n\tcase *VectorInt8:\n\t\treturn hybridVectorBytes(vector.Val)\n\tcase *VectorUint8:\n\t\treturn hybridVectorBytes(vector.Val)\n\tcase *VectorValues, *VectorRef:\n\t\treturn nil, fmt.Errorf(\"FT.HYBRID: unsupported vector type %T\", v)\n\tdefault:\n\t\tvalues := v.Value()\n\t\tif len(values) < 2 {\n\t\t\treturn nil, fmt.Errorf(\"FT.HYBRID: vector Value must contain a blob at index 1\")\n\t\t}\n\t\treturn values[1], nil\n\t}\n}\n\nfunc hybridVectorBytes(blob []byte) ([]byte, error) {\n\tif len(blob) == 0 {\n\t\treturn nil, fmt.Errorf(\"FT.HYBRID: vector blob is required\")\n\t}\n\treturn blob, nil\n}\n\n// generateVectorParamName returns a parameter name that is not already present\n// in params. It is used to pass vector data via the PARAMS mechanism when the\n// caller does not provide a VectorParamName, since inline vector blobs are no\n// longer supported by Redis.\nfunc generateVectorParamName(params map[string]interface{}) string {\n\tfor i := 0; ; i++ {","sourceCodeStart":3786,"sourceCodeEnd":3822,"githubUrl":"https://github.com/redis/go-redis/blob/c5cad058c72f58370553b48566302303cf8a2e89/search_commands.go#L3786-L3822","documentation":"For a custom Vector implementation in FT.HYBRID, the client calls Value() and expects [paramName, blob] with the raw binary vector data at index 1. If the returned slice has fewer than 2 elements, there is no blob to send and this error is returned.","triggerScenarios":"Passing a custom Vector type to FTHybridWithArgs whose Value() returns a slice of length 0 or 1 (e.g. only the parameter name, or an empty slice).","commonSituations":"Custom Vector implementations written for another command's contract returning just the float values; forgetting that FT.HYBRID needs name-then-blob ordering.","solutions":["Return at least two elements from Value(), with the encoded binary vector as element 1.","Reuse a built-in blob type like *VectorFP32 to avoid implementing Value() yourself.","Encode floats to little-endian bytes (or use VectorFP32's encoding) before returning them."],"exampleFix":"// before\nfunc (v *myVec) Value() []interface{} { return []interface{}{\"vec_param\"} }\n// after\nfunc (v *myVec) Value() []interface{} { return []interface{}{\"vec_param\", float32LEBytes(v.data)} }","handlingStrategy":"validation","validationCode":"vals := myVec.Value()\nif len(vals) < 2 {\n    return errors.New(\"custom Vector.Value() must return [name, blob]\")\n}","typeGuard":"func customVectorOK(v redis.Vector) bool {\n    return len(v.Value()) >= 2\n}","tryCatchPattern":"cmd := client.FTHybridWithArgs(ctx, \"idx\", opts)\nif err := cmd.Err(); err != nil && strings.Contains(err.Error(), \"blob at index 1\") {\n    // fix Value() implementation before retrying\n}","preventionTips":["Follow the [paramName, blob] contract in custom Vector implementations","Add a unit test asserting Value() arity","Prefer built-in blob types over custom implementations"],"tags":["search","vector","ft-hybrid","custom-implementation"],"backgroundTag":"missing-required-value","analyzedSha":"c5cad058c72f58370553b48566302303cf8a2e89","analyzedAt":"2026-09-01T06:50:53.388Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}