REST DSL: response marshalling failure is swallowed and returned as HTTP 200 with an empty `text/plain` body
- Dominant language
- Java
- Stars
- 302
- Forks
- 232
- Avg merge
- 1d 22h
- Merged PRs (30d)
- 108
Description
---
### Description
With `bindingMode(json)` on the REST DSL, if Jackson cannot marshal the response body, the caller
receives **HTTP 200 with an empty body and `Content-Type: text/plain; charset=utf-8`**. No error is
logged, no exception reaches the route's error handler, and the status code stays 200.
The concrete trigger in our case: the REST binding builds its **own** Jackson data format
(`RestBindingAdviceFactory.build()` → `camelContext.createDataFormat("jackson")`), which uses a
plain `ObjectMapper` rather than the application's configured CDI `ObjectMapper`. That plain mapper
has no `JavaTimeModule`, so **any response POJO containing a `java.time` field fails to marshal** —
even though `jackson-datatype-jsr310` and Quarkus' `quarkus-jackson` are on the classpath.
The silent 200 is the actual problem: a serialization failure is indistinguishable from a
successful empty response, so a client (or a browser app) just sees "no data" and everything
downstream fails in confusing ways. We lost a full day to this after a platform upgrade.
### Reproducer
Attached/linked project (4 files, no application code beyond a POJO and a `RouteBuilder`):
- `Item` — POJO with `int id`, `String name`, `LocalDateTime created`
- `Routes` — `restConfiguration().component("platform-http").bindingMode(json).contextPath("/api")`,
and three verbs (`GET /demo`, `GET /demo/{id}`, `POST /demo`) that all route to a processor
which returns `new Item(42, "demo")`
- `RestBindingTest` — asserts `200` + `application/json` + `id == 42` for all three
```
mvn test # 3 failures
mvn test -Dquarkus.platform.version=3.33.1 # 3 failures (same behaviour)
```
**Expected:** `200` + `application/json` + `{"id":42,...}`
**Actual:** `200` + `text/plain; charset=utf-8` + empty body, for all three verbs.
Remove the `LocalDateTime` field from `Item` and all three pass, which isolates the cause to the
marshalling step.
### Versions
- Camel Quarkus 3.39.1 (Camel 4.22.0) — and identically on Camel Quarkus 3.33.1
- Quarkus 3.39.1 / 3.33.1, JDK 21 and JDK 25 (both), Windows
- `camel-quarkus-rest`, `camel-quarkus-direct`, `camel-quarkus-jackson`, `quarkus-jackson`,
`jackson-datatype-jsr310` all on the classpath
Note: not reported as a regression — the reproducer behaves the same on 3.33.1 and 3.39.1.
### Where it happens
`org.apache.camel.support.processor.RestBindingAdvice#marshal` (camel-support 4.22.0):
```java
try {
if (isJson && jsonMarshal != null) {
if (contentType.contains("json")) {
jsonMarshal.process(exchange); // throws for java.time fields
...
}
}
...
} catch (Exception e) {
exchange.setException(e); // set after the route completed -> never surfaces
}
```
`marshal()` runs from `after()`, i.e. after the route has finished, so the exception set here is
not routed through `onException`/the error handler and the consumer writes the (unmarshalled,
unconvertible) body — which ends up as an empty `text/plain` response.
### Suggested fixes
1. **Make the failure visible.** A failed response marshal should produce a 500 (or at least an
ERROR log), never a 200 with an empty body.
2. **Consider defaulting `autoDiscoverObjectMapper` to `true`** for the REST DSL data format in
camel-quarkus, so the binding uses the application's configured `ObjectMapper`. As it stands, an
app can have `quarkus-jackson` fully configured (modules, date format, naming strategy) and the
REST layer still silently serializes with different, unconfigured settings.
### Workaround (works, for anyone hitting this)
```java
restConfiguration()
.component("platform-http")
.bindingMode(RestBindingMode.json)
.dataFormatProperty("json.in.autoDiscoverObjectMapper", "true")
.dataFormatProperty("json.out.autoDiscoverObjectMapper", "true");
```
[cq-binding-repro.zip](https://github.com/user-attachments/files/31559036/cq-binding-repro.zip)
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with org.apache.camel.support.processor.RestBindingAdvice#marshal and the RestBindingAdviceFactory.build() path described in the issue, then run the linked four-file reproducer with mvn test. Trace how the after() processing handles a Jackson failure and how the REST data format selects an ObjectMapper. Done means the LocalDateTime response no longer becomes a successful empty text/plain response and the reproducer verifies the intended error or configured-mapper behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100