apache / apache/camel-quarkus

REST DSL: response marshalling failure is swallowed and returned as HTTP 200 with an empty `text/plain` body

Open
#9,077 1 comment 0 reactions 0 assignees View on GitHub
area/rest
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.