Skip to content

[Cherry-pick to branch-1.3] [#12783] fix(server): return JSON errors for the whole pre-resource-method WebApplicationException family (#12878) - #12910

Merged
jerryshao merged 2 commits into
branch-1.3from
cherry-pick-deb1e2d2-to-branch-1.3
Sep 4, 2026
Merged

[Cherry-pick to branch-1.3] [#12783] fix(server): return JSON errors for the whole pre-resource-method WebApplicationException family (#12878)#12910
jerryshao merged 2 commits into
branch-1.3from
cherry-pick-deb1e2d2-to-branch-1.3

Conversation

@github-actions

@github-actions github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown

Cherry-pick Information:

  • Original commit: deb1e2d
  • Target branch: branch-1.3
  • Status: ⚠️ Has conflicts - manual resolution required

Do not merge until conflict markers are resolved and the
cherry-pick-conflict label is removed.

Please review and resolve the conflicts before merging.

…ethod WebApplicationException family (#12878)

### What changes were proposed in this pull request?

Follow-up to #12784. That PR registered `ParamExceptionMapper` (typed
parameter conversion failures) and `NotFoundExceptionMapper` (unmatched
routes), but those only cover two specific cases. Any other error
resolved
before reaching a resource method was still unmapped and fell through to
Jetty's default HTML error page.

This PR adds two fixes:

- `WebApplicationExceptionMapper`, registered on the common
`javax.ws.rs.WebApplicationException` base class as a catch-all for the
rest of the JAX-RS family — a wrong HTTP method (`NotAllowedException`,
405), an unsupported `Content-Type` (`NotSupportedException`, 415), etc.
JAX-RS always selects the mapper for the nearest type in an exception's
class hierarchy, so `ParamExceptionMapper` and `NotFoundExceptionMapper`
still take precedence for the cases they already handle. It preserves
the
  original response's headers (e.g. `Allow` on 405) via
`Response.fromResponse(...)`, and intentionally never preserves any
entity
the original response might carry, so every error under `/api/*` stays
the
  same `ErrorResponse` JSON shape.
- `VersioningFilter` now writes the JSON `ErrorResponse` directly
instead of
  calling `sendError` when it rejects an unsupported API version. This
filter runs *before* Jersey ever sees the request, so no
`ExceptionMapper`
— including the one above — can ever intercept it; this was the actual
406
case users hit. (Jersey's own `NotAcceptableException` is not reachable
through this API today, since `VersioningFilter` normalizes or rejects
the
version before Jersey runs; `WebApplicationExceptionMapper` still
handles
  it generically as defense-in-depth.)

Confirmed no existing code throws a raw `WebApplicationException`
subtype
expecting to reach the catch-all mapper with custom headers/entity: the
two
direct throws in `server/` (`NotSupportedException` in
`MetadataObjectSecretOperations`/`MetadataObjectCredentialOperations`)
and
two more in `core/` (`CredentialOperationDispatcher`,
`SecretPropertyOperationDispatcher`) are all already caught by a local
`try`/`catch` before ever reaching Jersey's provider chain.

Fix: #12783

### Why are the changes needed?

Stated generally (per review discussion on #12784 and this PR): any
error
resolved before reaching a resource method should return the same
structured JSON body as the rest of the API.

### Does this PR introduce _any_ user-facing change?

Yes, under `/api/*`:
- A wrong HTTP method (e.g. `POST /api/version`) now returns a
structured
JSON `ErrorResponse` — HTTP 405, type `UnsupportedOperationException` —
  instead of Jetty's default HTML error page.
- An unrecognized `Accept` API version (e.g.
  `application/vnd.gravitino.v99+json`) now returns a structured JSON
`ErrorResponse` — HTTP 406, type `IllegalArgumentException` — instead of
  an empty body with no `Content-Type`.

No other endpoint's behavior changes.

### How was this patch tested?

- `TestWebApplicationExceptionMapper` (unit test) covers
`NotAllowedException`
  (405, including the preserved `Allow` header), `NotSupportedException`
  (415), and `NotAcceptableException` (406).
- `TestVersioningFilter` updated to assert the new JSON `ErrorResponse`
body
(status, content type, and parsed `ErrorResponse` fields) instead of the
  old `sendError` call.
- `JsonErrorHandlerIT` (integration test against a real running server)
  covers a malformed model version, a malformed model version URI, an
  unmatched `/api/*` route, a wrong HTTP method, and an unsupported API
  version — all 5 pass.
- Ran the full `server` and `server-common` unit test suites; no
  regressions.

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
# Conflicts:
#	server/src/main/java/org/apache/gravitino/server/web/VersioningFilter.java
@github-actions github-actions Bot added cherry-pick Automatically opened cherry-pick PR cherry-pick-conflict Cherry-pick has conflicts; needs human resolution before merge labels Sep 4, 2026
@github-actions
github-actions Bot requested a review from jerryshao September 4, 2026 06:16
Adapts the JSON-error fix from deb1e2d to branch-1.3's older
VersioningFilter, which predates the versionFromHeaders/isUnsupportedVersion
refactor on main and still inlines version checking in doFilter. Also
updates the three TestVersioningFilter assertions that still expected the
old sendError call on an unsupported-version response, since branch-1.3
only supports API v1 and those call sites now hit the same JSON-error path.
@jerryshao jerryshao removed the cherry-pick-conflict Cherry-pick has conflicts; needs human resolution before merge label Sep 4, 2026
@jerryshao jerryshao changed the title [DO NOT MERGE] [Cherry-pick to branch-1.3] [#12783] fix(server): return JSON errors for the whole pre-resource-method WebApplicationException family (#12878) [Cherry-pick to branch-1.3] [#12783] fix(server): return JSON errors for the whole pre-resource-method WebApplicationException family (#12878) Sep 4, 2026
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Author

Code Coverage Report

Overall Project 68.66% +0.01% 🟢
Files changed 71.5% 🟢

Module Coverage
aliyun 19.74% 🔴
api 47.62% 🟢
authorization-common 85.96% 🟢
aws 53.54% 🟢
azure 32.1% 🔴
catalog-common 10.4% 🔴
catalog-fileset 80.51% 🟢
catalog-glue 69.24% 🟢
catalog-hive 79.42% 🟢
catalog-jdbc-clickhouse 84.7% 🟢
catalog-jdbc-common 45.47% 🟢
catalog-jdbc-doris 82.61% 🟢
catalog-jdbc-hologres 54.03% 🟢
catalog-jdbc-mysql 79.33% 🟢
catalog-jdbc-oceanbase 78.6% 🟢
catalog-jdbc-postgresql 83.39% 🟢
catalog-jdbc-starrocks 79.16% 🟢
catalog-kafka 77.27% 🟢
catalog-lakehouse-generic 59.35% 🟢
catalog-lakehouse-hudi 79.1% 🟢
catalog-lakehouse-iceberg 85.86% 🟢
catalog-lakehouse-paimon 82.17% 🟢
catalog-model 77.99% 🟢
cli 44.51% 🟢
client-java 78.31% 🟢
common 50.74% 🟢
core 82.96% 🟢
filesystem-hadoop3 77.3% 🟢
flink 0.0% 🔴
flink-common 49.22% 🟢
flink-runtime 0.0% 🔴
gcp 32.2% 🔴
hadoop-common 15.43% 🔴
hive-metastore-common 53.77% 🟢
iceberg-aliyun-bundle 0.0% 🔴
iceberg-common 58.18% 🟢
iceberg-rest-server 73.87% 🟢
idp-basic 86.02% 🟢
integration-test-common 0.0% 🔴
jobs 66.17% 🟢
lance-common 24.42% 🔴
lance-rest-server 60.13% 🟢
lineage 53.02% 🟢
optimizer 82.95% 🟢
optimizer-api 21.95% 🔴
server 88.55% -1.06% 🟢
server-common 76.28% 🟢
spark 28.57% 🔴
spark-common 41.66% 🟢
trino-connector 51.18% 🟢
Files
Module File Coverage
server VersioningFilter.java 97.83% 🟢
WebApplicationExceptionMapper.java 78.57% 🟢
GravitinoServer.java 61.65% 🟢

@jerryshao
jerryshao merged commit 7bec3c2 into branch-1.3 Sep 4, 2026
36 of 37 checks passed
@jerryshao
jerryshao deleted the cherry-pick-deb1e2d2-to-branch-1.3 branch September 4, 2026 07:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cherry-pick Automatically opened cherry-pick PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant