apache/druid · error

Query [ ] to host [ ] interrupted

Error message

Query [%s] to host [%s] interrupted

What it means

JsonParserIterator.convertException logs this warning when converting a Throwable received while pulling query results from a broker-to-historical HTTP stream into a QueryException. The original cause (e.g. a QueryException from DirectDruidClient) is preserved and rethrown with the host attached; conversion maps error codes to specific interrupt exception types.

Solutions

  1. Check the logged cause and host to find the failing data node and its error code
  2. Inspect the target host's logs for the original query failure
  3. Retry the query if the node restarted or the connection dropped
  4. Adjust timeout/cancellation settings if interrupts are systemic

Example fix

null
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

null

Try / catch

try { iterator.next(); } catch (QueryException e) { if (e.getErrorCode() == QUERY_CANCELED) { /* handle cancel */ } else { log.error("host failed: " + e.getHost()); } }

Prevention

When it happens

Trigger: next()/init() on the JSON-parsed result iterator encounter an exception: the HTTP stream from the target host failed, was cancelled, or a QueryException arrived whose errorCode needs remapping.

Common situations: Historical node restarts mid-query, query cancellation from the console, HTTP connection drops between broker and data node, timeouts surfacing as interrupts.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at server/src/main/java/org/apache/druid/client/JsonParserIterator.java:240

  }

  private QueryTimeoutException timeoutQuery()
  {
    return new QueryTimeoutException(StringUtils.nonStrictFormat("url[%s] timed out", url), host);
  }

  /**
   * Converts the given exception to a proper type of {@link QueryException}.
   * The use cases of this method are:
   * <p>
   * - All non-QueryExceptions are wrapped with {@link QueryInterruptedException}.
   * - The QueryException from {@link DirectDruidClient} is converted to a more specific type of QueryException
   * based on {@link QueryException#getErrorCode()}. During conversion, {@link QueryException#host} is overridden
   * by {@link #host}.
   */
  private QueryException convertException(Throwable cause)
  {
    LOG.warn(cause, "Query [%s] to host [%s] interrupted", queryId, host);
    if (cause instanceof QueryException) {
      final QueryException queryException = (QueryException) cause;
      if (queryException.getErrorCode() == null) {
        // errorCode should not be null now, but maybe could be null in the past...
        return new QueryInterruptedException(
            QueryException.UNKNOWN_EXCEPTION_ERROR_CODE,
            queryException.getMessage(),
            queryException.getErrorClass(),
            host
        );
      }

      // Note: this switch clause is to restore the 'type' information of QueryExceptions which is lost during
      // JSON serialization. As documented on the QueryException class, the errorCode of QueryException is the only
      // way to differentiate the cause of the exception.  This code does not cover all possible exceptions that
      // could come up and so, likely, doesn't produce exceptions reliably.  The only safe way to catch and interact
      // with a QueryException is to catch QueryException and check its errorCode.  In some future code change, we
      // should likely remove this switch entirely, but when we do that, we need to make sure to also adjust any

View on GitHub (pinned to 9b90983fd2)