redis/go-redis · error
invalid document fields format
Error message
invalid document fields format
What it means
The final element of each FT.SEARCH (RESP2) document entry must be the fields array (a []interface{} of key/value pairs), or nil when the document was deleted mid-index (which go-redis maps to doc.Error). Any other type at that position makes the parser fail with this error.
Source
Thrown at search_commands.go:2667
}
}
if withSortKeys && i < len(data) {
if sortKey, ok := data[i].(string); ok {
doc.SortKey = &sortKey
i++
}
}
if i < len(data) {
fields, ok := data[i].([]interface{})
if !ok {
if data[i] == proto.Nil || data[i] == nil {
doc.Error = proto.Nil
doc.Fields = map[string]string{}
fields = []interface{}{}
} else {
return FTSearchResult{}, fmt.Errorf("invalid document fields format")
}
}
for j := 0; j < len(fields); j += 2 {
key, ok := fields[j].(string)
if !ok {
return FTSearchResult{}, fmt.Errorf("invalid field key format")
}
value, ok := fields[j+1].(string)
if !ok {
return FTSearchResult{}, fmt.Errorf("invalid field value format")
}
doc.Fields[key] = value
}
i++
}
results = append(results, doc)View on GitHub (pinned to c5cad058c7)
Solutions
- Check the raw reply's element layout and confirm each doc ends with an array or nil
- Make FTSearchOptions flags match the FT.SEARCH arguments actually issued
- Fix proxies/hooks/mocks that reshape the reply
- Upgrade to matched go-redis/RediSearch versions
Example fix
// before: mock uses a map for fields
mock := []interface{}{int64(1), "doc:1", map[string]string{"t": "v"}}
// after: fields must be a flat array
cmd := rdb.FTSearch(ctx, "idx", "q")
mock := []interface{}{int64(1), "doc:1", []interface{}{"t", "v"}} Defensive patterns
Strategy: type-guard
Validate before calling
// Ensure the trailing element of each doc entry is an array or nil
last := mockDocEntry[len(mockDocEntry)-1]
switch last.(type) {
case []interface{}, nil:
default:
panic("fields element must be []interface{} or nil")
} Type guard
func isFieldsElement(v interface{}) bool {
if v == nil {
return true // deleted doc case
}
_, ok := v.([]interface{})
return ok
} Try / catch
res, err := rdb.FTSearch(ctx, "idx", q).Result()
if err != nil {
if strings.Contains(err.Error(), "invalid document fields") {
log.Printf("unexpected fields element in FT.SEARCH reply: %v", err)
return emptyDocs, nil
}
return err
} Prevention
- Model mocks on the real wire format: flat key/value arrays, not maps
- Remember go-redis treats a nil fields element as a deleted document (doc.Error)
- Keep NoContent/WithScores flags consistent with the issued command
When it happens
Trigger: FTSearch reply where the fields element is a string/map/int instead of an array or nil — typically a reply shape shifted by missing WithScores/WithPayloads elements, a proxy rewriting the reply, or a malformed mock.
Common situations: Options mismatch (NoContent false but server sent no fields array); custom middleware; non-RediSearch server; hand-crafted test data using a map for fields.
Related errors
- unexpected search result format
- invalid total results format
- invalid document ID format
- invalid score format
- invalid field value format
AI-assisted analysis of redis/go-redis@c5cad058c7 (2026-09-01).
Data as JSON: /api/errors/3ce84ba400945631.
Report an issue: GitHub.