redis/jedis · error · JedisException
Failed to fetch next aggregation batch
Error message
Failed to fetch next aggregation batch
What it means
Wraps any exception raised while obtaining the next aggregation batch (either returning the cached first result or executing the cursor's FT.CURSOR read via doFetch) into a JedisException. It indicates a runtime failure — connection error, bad reply, protocol issue — while advancing the aggregation cursor, not a normal end-of-results condition.
Solutions
- Catch JedisException and inspect the cause; if the cursor expired, restart the aggregation from the beginning
- Ensure iteration completes promptly or re-set a longer CURSOR TTL in the AggregationBuilder if batches are consumed slowly
- Check network stability and cluster health between batches; retry the whole aggregation with backoff on transient connection errors
- Log the wrapped cause to distinguish protocol/parse failures from connectivity failures
Example fix
// before
AggregationResult r = iterator.next(); // raw JedisException propagates
// after
try {
AggregationResult r = iterator.next();
} catch (JedisException e) {
// retry aggregation or inspect e.getCause() (expired cursor, connectivity)
restartAggregation();
} Defensive patterns
Strategy: try-catch
Validate before calling
// ensure cursor is still valid before continuing if you track it Long cursorId = iterator.getCursorId(); boolean cursorUsable = cursorId == null || cursorId > 0;
Type guard
null
Try / catch
try {
AggregationResult r = iterator.next();
} catch (JedisException e) {
Throwable cause = e.getCause();
// expired cursor / connectivity: log cause and restart the whole aggregation
restartAggregation();
} Prevention
- Consume batches promptly so the server-side cursor TTL doesn't expire; raise CURSOR TTL for slow consumers
- Monitor cluster/node health during long aggregations
- Log e.getCause() to distinguish expired-cursor from network failures
- Wrap the full iteration in a retry that rebuilds the aggregation from scratch
When it happens
Trigger: Any Exception thrown inside next(): borrowing a connection fails, the cursor command is rejected by the server (e.g. unknown/expired cursor), or the reply cannot be parsed into an AggregationResult.
Common situations: Cursor expired on the server (CURSOR TTL elapsed between batches); Redis node became unreachable mid-iteration; cluster resharding moved the cursor; serialization/parse errors on unexpected replies.
Understand the failure class
Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.
Related errors
- Failed to initialize aggregation cursor
- cursor must be set
- No connections available from connection provider
- No more aggregation results available
- is not supported.
AI-assisted analysis of redis/jedis@6dac31d4c2 (2026-09-08).
Data as JSON: /api/errors/caf4d014efc1c2a0.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/redis/clients/jedis/search/aggr/AggregateIterator.java:125
@Override
public AggregationResult next() {
if (!hasNext()) {
throw new NoSuchElementException("No more aggregation results available");
}
try {
if (aggrCommandResult != null) {
try {
return aggrCommandResult;
} finally {
aggrCommandResult = null;
}
} else {
return doFetch();
}
} catch (Exception e) {
throw new JedisException("Failed to fetch next aggregation batch", e);
}
}
/**
* Returns the current cursor ID.
* @return cursor ID, or null if not initialized
*/
public Long getCursorId() {
return cursorId;
}
@Override
public void remove() {
aggrCommandResult = null;
if (cursorId == null || cursorId <= 0) {
// Cursor is already closed or not initialized, nothing to do
return;View on GitHub (pinned to 6dac31d4c2)