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
- Read the status code and response body in the exception message to identify why the node rejected the request
- Verify the target URL points at a lookup-capable node with the /druid/listen/v1/lookups endpoint
- Fix the lookup spec JSON so the node accepts it (validate the spec schema)
- 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
- Validate lookup spec JSON against the schema before publishing updates
- Keep coordinator and lookup node Druid versions in sync
- Avoid pushing updates while nodes are restarting (rolling upgrade windows)
- Ensure target URLs point at lookup-listener ports, not coordinator ports
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
- GET request failed to
- Action [ ] failed for worker [ ] with status ( )
- An external HTTP table with a URI must also provide the…
- An external HTTP table with a URI must also provide the…
- AuthenticationToken ignored:
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)