quarkusio/quarkus · error · IllegalStateException

Response has been closed

Error message

Response has been closed

What it means

ResponseImpl.checkClosed() throws IllegalStateException when a Response that was closed() and is not buffered is accessed. Once closed, the underlying connection/stream is released, so getEntity, readEntity, hasEntity and bufferEntity refuse to operate. Buffered responses are exempt per the JAX-RS TCK.

Source

Thrown at independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/jaxrs/ResponseImpl.java:190

                    while ((read = entityStream.read(buffer)) != -1) {
                        os.write(buffer, 0, read);
                    }
                    entityStream.close();
                } catch (IOException x) {
                    throw new UncheckedIOException(x);
                }
                entityStream = new ByteArrayInputStream(os.toByteArray());
            }
            buffered = true;
            return true;
        }
        return false;
    }

    protected void checkClosed() {
        // apparently the TCK says that buffered responses don't care about being closed
        if (closed && !buffered)
            throw new IllegalStateException("Response has been closed");
    }

    @Override
    public void close() {
        if (!closed) {
            closed = true;
            if (entityStream != null) {
                try {
                    entityStream.close();
                } catch (IOException e) {
                    throw new ProcessingException(e);
                }
            }
        }
    }

    @Override
    public MediaType getMediaType() {

View on GitHub (pinned to e1c734241f)

Solutions

  1. Read the entity BEFORE closing the response; close in a finally/try-with-resources after consumption.
  2. Call bufferEntity() before close() if you need to access the entity multiple times or after closing.
  3. Remove the duplicate close() or the late access; don't share Response objects across async boundaries after closing.
  4. Restructure so the entity is extracted into a plain object within the response's scope.

Example fix

// before
try (Response response = client.target(url).request().get()) { /* nothing read here */ }
String body = response.readEntity(String.class); // IllegalStateException
// after
String body;
try (Response response = client.target(url).request().get()) {
    body = response.readEntity(String.class);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// guard before reading
if (response instanceof ResponseImpl) { /* or track closed state yourself */ }
boolean safeToRead = !responseClosed && (buffered || response.hasEntity());

Type guard

boolean canRead(javax.ws.rs.core.Response r) { try { return r.hasEntity(); } catch (IllegalStateException e) { return false; } }

Try / catch

try { return response.readEntity(String.class); } catch (IllegalStateException e) { log.warn("Response already closed; re-issue request or buffer beforehand", e); return null; }

Prevention

When it happens

Trigger: Calling readEntity()/getEntity() on a Response after close(); using a Response outside a try-with-resources after it has been auto-closed; accessing a Response in a listener/callback that runs after the request completed.

Common situations: Double-consumption patterns where code closes the response then logs the entity; caching a Response field and reading it later; framework code (filters/interceptors) that closed the response before downstream code reads it.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/f45594be6bfbb27d. Report an issue: GitHub.