apache/druid · error · RE

Unable to close continuation

Error message

Unable to close continuation

What it means

AbstractPartitioningOperator.handleNonGoCases closes the Continuation (cont.close()) after receiving a STOP signal. If closing the continuation throws IOException, it is rethrown as this RE, since a resource underlying the continuation could not be released.

Solutions

  1. Inspect the cause (RE wraps the IOException) to find the underlying I/O failure and address it (disk, file handle exhaustion)
  2. Retry the query; transient close failures usually indicate underlying storage trouble
  3. Report to maintainers if it reproduces consistently — the continuation implementation may be double-closing
Defensive patterns

Strategy: try-catch

Try / catch

try {
  operator.go(receiver, cont);
} catch (ResourceLimitExceededException | RE e) {
  if (e.getMessage() != null && e.getMessage().contains("Unable to close continuation")) {
    logger.warn(e.getCause(), "Continuation close failed; underlying resource may need cleanup");
  } else throw e;
}

Prevention

When it happens

Trigger: A downstream operator signals STOP (e.g. limit reached, query cancelled) and cont.close() — which may close an underlying file/channel resource — throws IOException during cleanup.

Common situations: Cancelling or early-terminating window operator queries over disk-backed segments where closing the backing resource hits an I/O error (device error, file already closed by another path).

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/8eb57cc4eb8d8737. Report an issue: GitHub.

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/query/operator/AbstractPartitioningOperator.java:166

        if (iter.hasNext()) {
          return HandleContinuationResult.of(cont);
        }

        if (cont.subContinuation == null) {
          // We were finished anyway
          receiver.completed();
          return HandleContinuationResult.of(null);
        }

        return HandleContinuationResult.of(new Continuation(null, cont.subContinuation));

      case STOP:
        receiver.completed();
        try {
          cont.close();
        }
        catch (IOException e) {
          throw new RE(e, "Unable to close continuation");
        }
        return HandleContinuationResult.of(null);

      default:
        throw new RE("Unknown signal[%s]", signal);
    }
  }

  protected static class Continuation implements Closeable
  {
    Iterator<RowsAndColumns> iter;
    Closeable subContinuation;

    public Continuation(Iterator<RowsAndColumns> iter, Closeable subContinuation)
    {
      this.iter = iter;
      this.subContinuation = subContinuation;
    }

View on GitHub (pinned to 9b90983fd2)