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
- Find the filter or handler that put the non-standard object into the response pipeline and make it return a proper ZuulMessage/HttpResponse type.
- Log msg.getClass() in a custom pipeline handler before write to identify the offending type and where it originates.
- Check custom filters compile against the zuul-core version in use — API changes across versions can change expected response types.
- 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
- Always return proper ZuulMessage/HttpResponse types from response filters
- Add a pipeline logging handler to catch unexpected message classes early in dev
- Keep custom filters compiled against the same zuul-core version as the server
- Never write raw Strings or ByteBufs directly to the client-facing pipeline
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)