Netflix/zuul · error · ZuulException

Attempt to write invalid content type to client

Error message

Attempt to write invalid content type to client: ${msg.getClass().getSimpleName()}

What it means

ClientRequestReceiver's outbound write handler only knows how to write Zuul's expected response types (ZuulMessage/HttpResponseContent variants). If an object of any other type reaches the client-facing pipeline write path, Zuul releases it and throws this error instead of silently corrupting the response stream. The code comments say this 'should never happen', so it indicates an internal invariant violation — a filter or handler passed an unsupported object into the response channel pipeline.

Solutions

  1. Find the filter or handler that put the non-standard object into the response pipeline and make it return a proper ZuulMessage/HttpResponse type.
  2. Log msg.getClass() in a custom pipeline handler before write to identify the offending type and where it originates.
  3. Check custom filters compile against the zuul-core version in use — API changes across versions can change expected response types.
  4. If a custom MessageFilter must transform content, wrap the result in the appropriate Zuul response content type rather than writing raw Netty buffers.

Example fix

// before (filter)
context.getResponse().setBody("raw string body");
return rawByteBuf;
// after
ZuulHttpResponse response = context.getResponse();
response.setBody(new byte[] {...}); // proper ZuulMessage body, not a raw object
return response;
Defensive patterns

Strategy: validation

Validate before calling

// before writing a response to the pipeline, assert it is a supported Zuul/Netty type
if (!(msg instanceof HttpResponse || msg instanceof HttpContent || msg instanceof ZuulMessage)) {
    throw new IllegalArgumentException("Unsupported response type: " + msg.getClass().getName());
}

Type guard

boolean isValidClientResponse(Object msg) {
    return msg instanceof HttpResponse || msg instanceof HttpContent || msg instanceof ZuulMessage;
}

Try / catch

try {
    ctx.write(msg);
} catch (ZuulException e) {
    if (e.getMessage().startsWith("Attempt to write invalid content type")) {
        log.error("Filter emitted invalid response type", e);
        ctx.writeAndFlush(HttpResponseStatus.INTERNAL_SERVER_ERROR);
    }
}

Prevention

When it happens

Trigger: A ZuulFilter mutates the response and returns/writes an unexpected object type (e.g. a raw String, ByteBuf, or custom object instead of HttpResponse/HttpContent-based ZuulMessage) that then flows to the client write path in ClientRequestReceiver.write.

Common situations: Custom endpoint or response filters written against the wrong API version returning raw objects; refactors that change filter output types; mixing Netty-native objects into Zuul response messages.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of Netflix/zuul@14bf53c52d (2026-09-07). Data as JSON: /api/errors/609f89cf4e1b1193. Report an issue: GitHub.

Appendix: source

Thrown at zuul-core/src/main/java/com/netflix/zuul/netty/server/ClientRequestReceiver.java:462

        try (TaskCloseable ignored = PerfMark.traceTask("CRR.write")) {
            if (msg instanceof HttpResponse) {
                promise.addListener((future) -> {
                    if (!future.isSuccess()) {
                        fireWriteError("response headers", future.cause(), ctx);
                    }
                });
                super.write(ctx, msg, promise);
            } else if (msg instanceof HttpContent) {
                promise.addListener((future) -> {
                    if (!future.isSuccess()) {
                        fireWriteError("response content", future.cause(), ctx);
                    }
                });
                super.write(ctx, msg, promise);
            } else {
                // should never happen
                ReferenceCountUtil.release(msg);
                throw new ZuulException(
                        "Attempt to write invalid content type to client: "
                                + msg.getClass().getSimpleName(),
                        true);
            }
        }
    }

    private void fireWriteError(String requestPart, Throwable cause, ChannelHandlerContext ctx) {

        String errMesg = String.format("Error writing %s to client", requestPart);

        if (cause instanceof java.nio.channels.ClosedChannelException
                || cause instanceof Errors.NativeIoException
                || cause instanceof SSLException
                || (cause.getCause() != null && cause.getCause() instanceof SSLException)
                || isStreamCancelled(cause)) {
            LOG.debug("{} - client connection is closed.", errMesg);
            if (zuulRequest != null) {

View on GitHub (pinned to 14bf53c52d)