quarkusio/quarkus · error · IllegalStateException

Could not find MessageBodyWriter for ${entityClass}

Error message

Could not find MessageBodyWriter for ${entityClass}

What it means

SseUtil.serialiseDataToString formats server-sent-event data by finding a MessageBodyWriter for the event's entity class and media type. If no registered writer can serialize the entity, it throws this IllegalStateException, so the SSE event cannot be written.

Source

Thrown at independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/SseUtil.java:146

        }
        // FIXME: this should belong somewhere else as it's generic
        @SuppressWarnings("unchecked")
        MessageBodyWriter<Object>[] writers = (MessageBodyWriter<Object>[]) serialisers
                .findWriters(null, entityClass, mediaType)
                .toArray(ServerSerialisers.NO_WRITER);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        boolean wrote = false;
        for (MessageBodyWriter<Object> writer : writers) {
            if (writer.isWriteable(entityClass, entityType, context.getAllAnnotations(), mediaType)) {
                // FIXME: spec doesn't really say what headers we should use here
                writer.writeTo(entity, entityClass, entityType, context.getAllAnnotations(), mediaType,
                        new QuarkusMultivaluedHashMap<>(), baos);
                wrote = true;
                break;
            }
        }
        if (!wrote) {
            throw new IllegalStateException("Could not find MessageBodyWriter for " + entityClass);
        }
        // At this point we can only pray that the resulting output is a UTF-8 string
        return baos.toString(StandardCharsets.UTF_8.name());
    }

    public static void setHeaders(ResteasyReactiveRequestContext context, ServerHttpResponse response) {
        setHeaders(context, response, Collections.emptyList());
    }

    public static void setHeaders(ResteasyReactiveRequestContext context, ServerHttpResponse response,
            List<PublisherResponseHandler.StreamingResponseCustomizer> customizers) {
        if (!response.headWritten()) {
            response.setStatusCode(Response.Status.OK.getStatusCode());
            response.setResponseHeader(HttpHeaders.CONTENT_TYPE, MediaType.SERVER_SENT_EVENTS);
            if (context.getTarget().getStreamElementType() != null) {
                response.setResponseHeader(SSE_CONTENT_TYPE, context.getTarget().getStreamElementType().toString());
            }
            response.setChunked(true);

View on GitHub (pinned to e1c734241f)

Solutions

  1. Add the missing serialization extension (e.g. quarkus-rest-jackson or quarkus-rest-jsonb) so POJOs can be written.
  2. Send a String or use .data(obj, MediaType.APPLICATION_JSON_TYPE) so a JSON writer applies to the event.
  3. Register a custom MessageBodyWriter for the entity class and its media type.
  4. Set the event's media type explicitly in the SseEventBuilder to match a writer you have available.

Example fix

// before
eventBuilder.data(myPojo); // no writer for text/plain
// after
eventBuilder.data(myPojo, MediaType.APPLICATION_JSON_TYPE); // with quarkus-rest-jackson on classpath
Defensive patterns

Strategy: validation

Validate before calling

// before sending an SSE event, confirm a writer exists for the entity and media type
if (jakarta.ws.rs.ext.RuntimeDelegate.getInstance() != null) {
    // or check your provider registry: writers.containsKey(new MediaTypeKey(entityClass, mediaType))
}
// simplest guard: only send types known to have writers
if (!(data instanceof String || data instanceof Number)) {
    ensureJsonWriterRegistered(data.getClass());
}

Type guard

static boolean hasKnownSseWriter(Object data) {
    return data instanceof String || data instanceof Number || data instanceof Boolean
        || jsonExtensionOnClasspath(); // quarkus-rest-jackson / quarkus-rest-jsonb
}

Try / catch

try {
    String s = SseUtil.serialiseDataToString(context, data, mediaType);
    emitter.send(s);
} catch (IllegalStateException e) {
    if (e.getMessage().startsWith("Could not find MessageBodyWriter")) {
        log.error("Register a MessageBodyWriter for " + data.getClass() + " or send JSON with an explicit media type");
    }
    throw e;
}

Prevention

When it happens

Trigger: Sending an object over an SSE endpoint (OutboundSseEvent.data(obj) / SseEventBuilder) whose class has no MessageBodyWriter for the negotiated media type (typically text/plain or the event's media type) — e.g. sending a POJO without a writer for text/plain.

Common situations: Emitting custom POJOs over SSE without registering a writer; relying on JSON writers while the SSE event media type defaults to text/plain; sending types unsupported by the installed extensions (e.g. missing RESTEasy Jackson/JSON-B dependency).

Related errors


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