apache/druid · error · IOException

Bad update request to

Error message

Bad update request to [%s] : [%d] : [%s]  Response: [%s]

What it means

updateNode() throws this IOException when the HTTP POST to a lookup node's update endpoint returns a non-2xx status code. The message embeds the URL, status code, reason phrase, and whatever of the response body could be read, so the caller can see why the node rejected the update.

Solutions

  1. Read the status code and response body in the exception message to identify why the node rejected the request
  2. Verify the target URL points at a lookup-capable node with the /druid/listen/v1/lookups endpoint
  3. Fix the lookup spec JSON so the node accepts it (validate the spec schema)
  4. Confirm coordinator and lookup node versions are compatible; upgrade mismatched nodes

Example fix

// before
// posting to wrong port/path
String url = "http://node:8081/druid/listen/v1/lookups"; // wrong service
// after
String url = "http://node:8080/druid/listen/v1/lookups"; // correct lookup listener port
Defensive patterns

Strategy: try-catch

Try / catch

try {
  coordinator.updateNode(host, lookupMap);
} catch (IOException e) {
  String msg = e.getMessage();
  if (msg != null && msg.startsWith("Bad update request")) {
    int code = parseStatusCode(msg); // inspect embedded status code
    LOG.error("Lookup node rejected update with HTTP %d", code);
  }
}

Prevention

When it happens

Trigger: POSTing lookup updates to a node whose HTTP endpoint responds 4xx/5xx — e.g. malformed update payload JSON, node not fully started, endpoint returning 404 because the node runs a version without the lookups endpoint, or 503 during node shutdown.

Common situations: Version skew between coordinator and lookup nodes (old nodes lacking the update API), invalid lookup spec/config rejected by the node, hitting a node during restart or rolling upgrade, wrong Druid node type addressed (non-lookup service in the tier).

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


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

Appendix: source

Thrown at server/src/main/java/org/apache/druid/server/lookup/cache/LookupCoordinatorManager.java:826

            LOG.debug(
                "Update on [%s], Status: %s reason: [%s], Response [%s].", url, returnCode.get(), reasonString.get(),
                response
            );
            return response;
          }
          catch (IOException ex) {
            throw new IOE(ex, "Failed to parse update response from [%s]. response [%s]", url, result);
          }
        } else {
          final ByteArrayOutputStream baos = new ByteArrayOutputStream();
          try {
            StreamUtils.copyAndClose(result, baos);
          }
          catch (IOException e2) {
            LOG.warn(e2, "Error reading response");
          }

          throw new IOE(
              "Bad update request to [%s] : [%d] : [%s]  Response: [%s]",
              url,
              returnCode.get(),
              reasonString.get(),
              StringUtils.fromUtf8(baos.toByteArray())
          );
        }
      }
    }

    public LookupsState<LookupExtractorFactoryMapContainer> getLookupStateForNode(
        HostAndPortWithScheme node
    ) throws IOException, InterruptedException, ExecutionException
    {
      final URL url = getLookupsURL(node);
      final AtomicInteger returnCode = new AtomicInteger(0);
      final AtomicReference<String> reasonString = new AtomicReference<>(null);

View on GitHub (pinned to 9b90983fd2)