{"record":{"id":"609f89cf4e1b1193","repo":"Netflix/zuul","slug":"attempt-to-write-invalid-content-type-to-client","errorCode":null,"errorMessage":"Attempt to write invalid content type to client: ${msg.getClass().getSimpleName()}","messagePattern":"Attempt to write invalid content type to client: (.+?)","errorType":"exception","errorClass":"ZuulException","httpStatus":null,"severity":"error","filePath":"zuul-core/src/main/java/com/netflix/zuul/netty/server/ClientRequestReceiver.java","lineNumber":462,"sourceCode":"        try (TaskCloseable ignored = PerfMark.traceTask(\"CRR.write\")) {\n            if (msg instanceof HttpResponse) {\n                promise.addListener((future) -> {\n                    if (!future.isSuccess()) {\n                        fireWriteError(\"response headers\", future.cause(), ctx);\n                    }\n                });\n                super.write(ctx, msg, promise);\n            } else if (msg instanceof HttpContent) {\n                promise.addListener((future) -> {\n                    if (!future.isSuccess()) {\n                        fireWriteError(\"response content\", future.cause(), ctx);\n                    }\n                });\n                super.write(ctx, msg, promise);\n            } else {\n                // should never happen\n                ReferenceCountUtil.release(msg);\n                throw new ZuulException(\n                        \"Attempt to write invalid content type to client: \"\n                                + msg.getClass().getSimpleName(),\n                        true);\n            }\n        }\n    }\n\n    private void fireWriteError(String requestPart, Throwable cause, ChannelHandlerContext ctx) {\n\n        String errMesg = String.format(\"Error writing %s to client\", requestPart);\n\n        if (cause instanceof java.nio.channels.ClosedChannelException\n                || cause instanceof Errors.NativeIoException\n                || cause instanceof SSLException\n                || (cause.getCause() != null && cause.getCause() instanceof SSLException)\n                || isStreamCancelled(cause)) {\n            LOG.debug(\"{} - client connection is closed.\", errMesg);\n            if (zuulRequest != null) {","sourceCodeStart":444,"sourceCodeEnd":480,"githubUrl":"https://github.com/Netflix/zuul/blob/14bf53c52dcf571894619ff65a674cbe2cce3ac6/zuul-core/src/main/java/com/netflix/zuul/netty/server/ClientRequestReceiver.java#L444-L480","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (filter)\ncontext.getResponse().setBody(\"raw string body\");\nreturn rawByteBuf;\n// after\nZuulHttpResponse response = context.getResponse();\nresponse.setBody(new byte[] {...}); // proper ZuulMessage body, not a raw object\nreturn response;","handlingStrategy":"validation","validationCode":"// before writing a response to the pipeline, assert it is a supported Zuul/Netty type\nif (!(msg instanceof HttpResponse || msg instanceof HttpContent || msg instanceof ZuulMessage)) {\n    throw new IllegalArgumentException(\"Unsupported response type: \" + msg.getClass().getName());\n}","typeGuard":"boolean isValidClientResponse(Object msg) {\n    return msg instanceof HttpResponse || msg instanceof HttpContent || msg instanceof ZuulMessage;\n}","tryCatchPattern":"try {\n    ctx.write(msg);\n} catch (ZuulException e) {\n    if (e.getMessage().startsWith(\"Attempt to write invalid content type\")) {\n        log.error(\"Filter emitted invalid response type\", e);\n        ctx.writeAndFlush(HttpResponseStatus.INTERNAL_SERVER_ERROR);\n    }\n}","preventionTips":["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"],"tags":["netty","zuul-filter","internal-invariant","response-pipeline"],"backgroundTag":"internal-invariant-violation","analyzedSha":"14bf53c52dcf571894619ff65a674cbe2cce3ac6","analyzedAt":"2026-09-07T10:00:54.873Z","contentChangedAt":"2026-09-07T10:00:54.873Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}