Netflix/zuul · error · ZuulException

Received invalid message from client

Error message

Received invalid message from client

What it means

OriginResponseReceiver.writeInternal writes messages from the client side toward the origin connection and only accepts valid Zuul request/HTTP message types. If a write arrives with any other type, Zuul releases it and throws this error, since forwarding an unrecognized object to the origin would corrupt the proxied request. The 'should never happen' comment marks it as an internal invariant guard.

Solutions

  1. Locate the filter writing the invalid object (log msg.getClass() before the write) and convert it to the proper ZuulMessage/HttpRequest type.
  2. Ensure request filters set data via the Zuul session/message API (e.g. zuulRequest buffers/headers) rather than writing custom objects to the channel.
  3. Align custom filter code and zuul-core versions so request message types match.
  4. Audit pipeline customizations in the origin channel init for handlers that fire non-HTTP messages.

Example fix

// before (custom request filter)
ctx.write(myCustomPayload);
// after
context.getZuulRequest().setBody(payloadBytes); // mutate the Zuul request message, don't write foreign objects
Defensive patterns

Strategy: validation

Validate before calling

// before writing toward the origin, assert the message is a supported Zuul/Netty request type
if (!(msg instanceof HttpRequest || msg instanceof HttpContent || msg instanceof ZuulMessage)) {
    throw new IllegalArgumentException("Unsupported request message: " + msg.getClass().getName());
}

Type guard

boolean isValidOriginRequest(Object msg) {
    return msg instanceof HttpRequest || msg instanceof HttpContent || msg instanceof ZuulMessage;
}

Try / catch

try {
    ctx.write(msg);
} catch (ZuulException e) {
    if ("Received invalid message from client".equals(e.getMessage())) {
        log.error("Filter wrote invalid object to origin pipeline", e);
        promise.setFailure(e);
    }
}

Prevention

When it happens

Trigger: An object that is not a recognized Zuul request message (e.g. raw String, ByteBuf, or custom object) is written into the origin-bound pipeline — typically from a custom pre-origin ZuulFilter or handler writing a foreign object type.

Common situations: Custom request filters mutating session/context and returning raw objects; version mismatches between custom filter code and zuul-core message APIs; errant pipeline handlers forwarding non-HTTP messages during proxying.

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/f471fde9ac55528e. Report an issue: GitHub.

Appendix: source

Thrown at zuul-core/src/main/java/com/netflix/zuul/netty/server/OriginResponseReceiver.java:256

                        fireWriteError("request headers", future.cause(), ctx);
                    }
                }
            });

            preWriteHook(ctx, zuulReq);

            super.write(ctx, buildOriginHttpRequest(zuulReq), promise);
        } else if (msg instanceof HttpContent) {
            promise.addListener((future) -> {
                if (!future.isSuccess()) {
                    fireWriteError("request content chunk", future.cause(), ctx);
                }
            });
            super.write(ctx, msg, promise);
        } else {
            // should never happen
            ReferenceCountUtil.release(msg);
            throw new ZuulException("Received invalid message from client", true);
        }
    }

    /**
     * Override to add custom pre-write functionality
     *
     * @param ctx     channel handler context
     * @param zuulReq request message to modify
     */
    protected void preWriteHook(ChannelHandlerContext ctx, HttpRequestMessage zuulReq) {}

    private void fireWriteError(String requestPart, Throwable cause, ChannelHandlerContext ctx) {
        String errMesg = "Error while proxying " + requestPart + " to origin ";
        if (edgeProxy != null) {
            ProxyEndpoint ep = edgeProxy;
            edgeProxy = null;
            errMesg += ep.getOrigin().getName();
            ep.errorFromOrigin(cause);

View on GitHub (pinned to 14bf53c52d)