eclipse-vertx/vert.x · error · IllegalStateException
A push response cannot promise another push
Error message
A push response cannot promise another push
What it means
In HTTP/2 server push, the response sent for a pushed resource is itself an HttpServerResponseImpl flagged with push=true. Such a push response must not initiate further pushes (the spec forbids nested push promises), so push() on a push response throws IllegalStateException.
Source
Thrown at vertx-core/src/main/java/io/vertx/core/http/impl/HttpServerResponseImpl.java:721
@Override
public long streamId() {
return stream.id();
}
@Override
public Future<Void> reset(long code) {
return stream.writeReset(code);
}
@Override
public Future<Boolean> cancel() {
return stream.cancel();
}
@Override
public Future<HttpServerResponse> push(HttpMethod method, HostAndPort authority, String path, MultiMap headers) {
if (push) {
throw new IllegalStateException("A push response cannot promise another push");
}
if (authority == null) {
authority = requestAuthority;
}
synchronized (conn) {
checkValid();
}
HostAndPort h = authority;
Future<HttpServerStream> fut = stream.sendPush(authority, method, headers, path, stream.priority());
return fut.map(pushStream -> {
HttpServerResponseImpl response = new HttpServerResponseImpl(pushStream, context, true);
response.requestMethod = method;
response.requestAuthority = h;
PushStreamHandler push = new PushStreamHandler(pushStream, response, context);
push.init();
return push.response;
});
}View on GitHub (pinned to fb308bd8c3)
Solutions
- Only call push() on the original request's response, never inside the pushHandler's response
- Track whether a response is a push response and skip push logic for it
- Refactor resource-pushing code to check a flag before invoking push()
Example fix
// before
response.pushHandler(pushedRes -> {
pushedRes.push(method, host, path); // IllegalStateException: nested push
});
// after
response.pushHandler(pushedRes -> {
// serve the pushed resource, do NOT push again from it
pushedRes.putHeader("Content-Type", "text/plain").end("pushed");
}); Defensive patterns
Strategy: validation
Validate before calling
// only push from the original response, never inside pushHandler
if (!isPushResponse(response)) {
response.push(method, authority, path);
} Try / catch
try {
response.push(method, authority, path);
} catch (IllegalStateException e) {
// this is a push response; nested push not allowed
} Prevention
- Never call push() from within a pushHandler's response
- Guard push logic with an isPush flag
- Keep push initiation in top-level request handlers only
When it happens
Trigger: Calling response.push(...) on the HttpServerResponse obtained from the pushHandler (the response you send for a pushed resource), instead of on the original client-initiated response.
Common situations: Recursive push logic that pushes resources found in any response, including push responses; generic handlers applied to push responses that unconditionally call push().
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Already a codec registered with name
- Already a default codec registered for class
- Already started
- address not specified
- Event Bus is not started
AI-assisted analysis of eclipse-vertx/vert.x@fb308bd8c3 (2026-09-06).
Data as JSON: /api/errors/c14ecb8837263e27.
Report an issue: GitHub.