redis/jedis · error · UnsupportedOperationException
binary ft.search is not implemented with resp3.
Error message
binary ft.search is not implemented with resp3.
What it means
The deprecated byte[]-based ftSearch(byte[], Query) in CommandObjects refuses to run under the RESP3 protocol because the binary search command path has not been implemented for RESP3. It throws UnsupportedOperationException before building the CommandObject.
Solutions
- Use the String-based ftSearch(String indexName, Query query) overload which supports RESP3
- Connect with RedisProtocol.RESP2 if the binary byte[] overload must be kept
- Encode index name once with SafeEncoder and switch code to the String API
Example fix
// before
SearchResult r = client.ftSearch("idx".getBytes(), query); // RESP3 -> throw
// after
SearchResult r = client.ftSearch("idx", query); // RESP3-safe Defensive patterns
Strategy: fallback
Validate before calling
if (indexName instanceof byte[] && clientProtocol == RedisProtocol.RESP3) { /* switch to String overload or RESP2 */ } Type guard
static boolean binarySearchUnsupported(RedisProtocol p) { return p == RedisProtocol.RESP3; } Try / catch
try { return client.ftSearch(indexBytes, query); } catch (UnsupportedOperationException e) { return client.ftSearch(new String(indexBytes, StandardCharsets.UTF_8), query); } Prevention
- Prefer the String-based ftSearch overloads
- Do not use the deprecated byte[] ftSearch in new code
- Pin RESP2 if legacy binary search paths are required
When it happens
Trigger: Calling ftSearch(byte[] indexName, Query query) while the client was negotiated/configured to use RedisProtocol.RESP3 (e.g. connected to Redis 6+ with default protocol RESP3).
Common situations: Migrating from legacy Jedis search usage to Redis 7+/RESP3 connections; using the deprecated binary overload because code passes byte[] index names; upgrading the server or setting protocol to RESP3 without noticing this overload is unimplemented.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- DIALECT=0 cannot be set.
- HELLO response is missing the protocol version field
- Client-side caching is only supported with RESP3.
- Client-side caching is only supported with RESP3.
- Range must not be null.
AI-assisted analysis of redis/jedis@6dac31d4c2 (2026-09-08).
Data as JSON: /api/errors/1ce69b9ba9e18e00.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/redis/clients/jedis/CommandObjects.java:4184
}
public final CommandObject<SearchResult> ftSearch(String indexName, String query, FTSearchParams params) {
return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.SEARCH, indexName)
.add(query).addParams(params.dialectOptional(searchDialect.get())),
getSearchResultBuilder(params.getReturnFieldDecodeMap(), () -> new SearchResultBuilder(
!params.getNoContent(), params.getWithScores(), true, params.getReturnFieldDecodeMap())));
}
public final CommandObject<SearchResult> ftSearch(String indexName, Query query) {
return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.SEARCH, indexName)
.addParams(query.dialectOptional(searchDialect.get())), getSearchResultBuilder(null,
() -> new SearchResultBuilder(!query.getNoContent(), query.getWithScores(), true)));
}
@Deprecated
public final CommandObject<SearchResult> ftSearch(byte[] indexName, Query query) {
if (protocol == RedisProtocol.RESP3) {
throw new UnsupportedOperationException("binary ft.search is not implemented with resp3.");
}
return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.SEARCH, indexName)
.addParams(query.dialectOptional(searchDialect.get())), getSearchResultBuilder(null,
() -> new SearchResultBuilder(!query.getNoContent(), query.getWithScores(), false)));
}
public final CommandObject<String> ftExplain(String indexName, Query query) {
return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.EXPLAIN, indexName)
.addParams(query.dialectOptional(searchDialect.get())), BuilderFactory.STRING);
}
public final CommandObject<List<String>> ftExplainCLI(String indexName, Query query) {
return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.EXPLAINCLI, indexName)
.addParams(query.dialectOptional(searchDialect.get())), BuilderFactory.STRING_LIST);
}
public final CommandObject<AggregationResult> ftAggregate(String indexName, AggregationBuilder aggr) {
return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.AGGREGATE, indexName)View on GitHub (pinned to 6dac31d4c2)