Skip to content

chore(backend): migrate HTTP 422 title from UNPROCESSABLE_ENTITY to UNPROCESSABLE CONTENT (per RFC 9110) - #7142

Open
corneliusroemer-agent wants to merge 2 commits into
mainfrom
chore/spring7-unprocessable-content
Open

chore(backend): migrate HTTP 422 title from UNPROCESSABLE_ENTITY to UNPROCESSABLE CONTENT (per RFC 9110)#7142
corneliusroemer-agent wants to merge 2 commits into
mainfrom
chore/spring7-unprocessable-content

Conversation

@corneliusroemer-agent

@corneliusroemer-agent corneliusroemer-agent commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator

Fix backend warnings 'val isUnprocessableEntity: ResultMatcher' is deprecated. Deprecated in Java.

Spring Framework 7 (Boot 4.1.0) follows RFC 9110 §15.5.21 in renaming HTTP 422 from Unprocessable Entity to Unprocessable Content.

⚠️ Note: the 422 response title changes, in line with RFC 9110

 {
   "type": "about:blank",
-  "title": "Unprocessable Entity",
+  "title": "Unprocessable Content",
   "status": 422,
   "detail": "..."
 }

🚀 Preview: https://chore-spring7-unprocessab.loculus.org

Spring Framework 7 follows RFC 9110 in renaming HTTP 422 from "Unprocessable
Entity" to "Unprocessable Content", deprecating HttpStatus.UNPROCESSABLE_ENTITY
and StatusResultMatchers.isUnprocessableEntity(). Those two accounted for every
one of the 94 Kotlin compiler warnings in the backend build.

The test matchers assert on the status code, which is unchanged, so that rename
is mechanical. Two of the three main-source uses are inert: @ResponseStatus sets
no reason attribute, and SubmissionMetrics tags with status.value() -> "422".

The one behavioural change is that ExceptionHandler derives the ProblemDetail
title from the status reason phrase, so 422 responses now report
title "Unprocessable Content" instead of "Unprocessable Entity". Spring already
treated the new phrase as canonical -- HttpStatus.valueOf(422) returns
UNPROCESSABLE_CONTENT, so any 422 without an explicitly set title already
rendered it -- and nothing branches on the title: the website parses it as an
opaque string and the preprocessing pipeline matches on the status code.

compileKotlin + compileTestKotlin warnings: 94 -> 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Claude finished @corneliusroemer-agent's task in 3m 41s —— View job


Review: chore(backend): use Spring 7 UNPROCESSABLE_CONTENT (422) API

  • Gather context (diff, changed files)
  • Review main-source changes (ExceptionHandler, SubmissionController)
  • Verify no stale UNPROCESSABLE_ENTITY / isUnprocessableEntity / "Unprocessable Entity" remain
  • Check downstream consumers (website, preprocessing, ingest, ena-submission, cli, docs, integration-tests)
  • Post review

Clean deprecation cleanup. I verified the PR description's claims rather than taking them at face value; they hold up.

Diff is genuinely mechanical. All 218 changed lines under backend/src/test/ match one of the six rename patterns — zero non-mechanical edits. Together with 3+3 in main sources and 1+1 in the website fixture that accounts for all 113/113.

Downstream consumers checked — none break.

Consumer How it matches 422 Affected
preprocessing/.../backend.py:161 case HTTPStatus.UNPROCESSABLE_ENTITY (integer 422) No
website/.../DataUploadForm.tsx:636 case 422: on error.response.status; ignores title on that branch No
website/.../backendApi.ts { status: 422, schema: problemDetail }; title is an opaque z.string() No
metrics/SubmissionMetrics.kt:57 .tag(STATUS_TAG, status.value().toString())"422" No
cli/, ena-submission/, ingest/, integration-tests/, docs/ no 422 / Unprocessable references at all No

No checked-in OpenAPI snapshot to regenerate (backend/docs/ holds only PlantUML + schema.sql), and no docs page documents ProblemDetail titles.

The title behaviour change is correctly scoped. ExceptionHandler.responseEntity sets title = httpStatus.reasonPhrase explicitly (ExceptionHandler.kt:126), so this really is the one visible change, and it moves 422 onto the phrase Spring already treats as canonical for HttpStatus.valueOf(422). Calling it out in the PR body was the right call — it is externally visible on the public API, even if nothing in this repo branches on it.

Nits (neither blocking):

  • One inline comment on stale exception names in ExceptionHandlerTest.
  • Test display names are now inconsistent: ExceptionHandlerTest says "Unprocessable Content", while ~25 names elsewhere still say "unprocessable entity" (e.g. SubmitProcessedDataEndpointTest.kt:262, SeqSetValidationEndpointsTest.kt:40). Purely cosmetic — the domain class is still UnprocessableEntityException, so leaving the prose as "entity" is defensible; just pick one direction. Fix this →

Not verified locally: I could not run ./gradlew in this environment (permission denied), so I relied on CI. backend-image (compiles main sources) and website-tests both passed, confirming HttpStatus.UNPROCESSABLE_CONTENT resolves under Boot 4.1.0. backend-tests and Integration tests were still running when I finished — those are what actually exercise status().isUnprocessableContent, so please confirm they go green before merging.

No security, performance, or error-handling concerns: no logic, control flow, queries, or resource handling were touched.
· chore/spring7-unprocessable-content

@claude claude Bot added backend related to the loculus backend component website Tasks related to the web application labels Aug 24, 2026
@claude

claude Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

This PR may be related to: #6976 and #7103.

Flagging for awareness; this PR does not claim to close either issue.

Comment thread backend/src/test/kotlin/org/loculus/backend/controller/ExceptionHandlerTest.kt Outdated
@corneliusroemer corneliusroemer changed the title chore(backend): use Spring 7 UNPROCESSABLE_CONTENT (422) API chore(backend): use Spring 7's UNPROCESSABLE_CONTENT for( 422) instead of UNPROCESSABLE_ENTITY Aug 24, 2026
…hrow

Both test names referenced exception classes that no longer exist:
InvalidSequenceFileException was removed in 694bda1, and ProcessingException
never existed as a class. Neither appeared anywhere in the repo outside these
two names, while the bodies throw UnprocessableEntityException and
ProcessingValidationException respectively.

Matches the sibling test, which names the exception it throws.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@corneliusroemer
corneliusroemer marked this pull request as draft August 24, 2026 10:59
@corneliusroemer corneliusroemer changed the title chore(backend): use Spring 7's UNPROCESSABLE_CONTENT for( 422) instead of UNPROCESSABLE_ENTITY chore(backend): use Spring 7's UNPROCESSABLE_CONTENT for HTTP 422 instead of UNPROCESSABLE_ENTITY Aug 24, 2026
@corneliusroemer corneliusroemer changed the title chore(backend): use Spring 7's UNPROCESSABLE_CONTENT for HTTP 422 instead of UNPROCESSABLE_ENTITY chore(backend): migrate HTTP 422 title from UNPROCESSABLE_ENTITY to UNPROCESSABLE CONTENT (per RFC 9110) Aug 24, 2026
@corneliusroemer
corneliusroemer marked this pull request as ready for review August 24, 2026 11:07
@corneliusroemer
corneliusroemer requested review from anna-parker, maverbiest and tombch and a lite review from Copilot August 24, 2026 11:07
@claude

claude Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Claude finished @corneliusroemer's task in 1m 36s —— View job


Review: chore(backend): migrate HTTP 422 title to UNPROCESSABLE_CONTENT

  • Gather context (diff, new commit)
  • Verify the rename is complete and mechanical
  • Re-check downstream consumers
  • Check CI status
  • Post review

Re-reviewed after 891ba3e, which fixes the stale exception names I flagged inline last round (InvalidSequenceFileExceptionUnprocessableEntityException, ProcessingExceptionProcessingValidationException). Nothing blocking. LGTM.

Rename is complete. Repo-wide, the only surviving UNPROCESSABLE_ENTITY is preprocessing/nextclade/src/loculus_preprocessing/backend.py:161, which is Python's stdlib HTTPStatus enum (integer 422) — unrelated to Spring and correctly left alone. All 113 changed lines are one of six mechanical patterns; I spot-checked the largest file (ReviseEndpointTest.kt, 46 lines) and found no non-mechanical edits.

One user-visible consequence beyond what the PR body notes. SeqSetForm.tsx:237,256,272 interpolates the ProblemDetail title verbatim into the error toast:

openErrorFeedback(`Failed to create seqSet. ${responseData.title}. ${responseData.detail}`);

and SeqSetEndpointsTest.kt:203 confirms seqset creation returns 422 for invalid accessions. So a user creating a seqset with a bad accession will now see "Failed to create seqSet. Unprocessable Content. …" instead of "… Unprocessable Entity. …". Not a regression — arguably neither phrase means anything to a submitter, which is exactly #6976. Just worth knowing the change reaches the UI, not only the API.

Everything else checked and unaffected: DataUploadForm.tsx:636 handles 422 with detail only; SubmissionForm.spec.tsx:221 uses a dummy title; backendApi.ts types title as an opaque z.string(); SubmissionMetrics tags on status.value() ("422"). No checked-in OpenAPI snapshot and no docs page pins the title.

CI: backend-tests ✅ (this is the job that actually exercises status().isUnprocessableContent), backend-image ✅, website-tests ✅, CodeQL ✅. Integration tests still in progress at time of writing — worth a glance before merge, though nothing in this diff should touch it.

No security, performance, or error-handling concerns: no logic, control flow, queries, or resource handling changed.
· chore/spring7-unprocessable-content

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Migrates HTTP 422 handling to Spring Framework 7’s RFC 9110 terminology, changing the title to “Unprocessable Content.”

Changes:

  • Replaces deprecated 422 status constants and matchers.
  • Updates backend assertions and website fixtures.
  • Updates exception handling and metrics status usage.

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated no comments.

Show a summary per file
File Summary
website/src/services/backendClient.spec.ts Updates the 422 title fixture.
backend/src/test/kotlin/org/loculus/backend/service/submission/UseNewerProcessingPipelineVersionTaskTest.kt Updates 422 assertions.
backend/src/test/kotlin/org/loculus/backend/controller/submission/SubmitProcessedDataEndpointTest.kt Updates 422 assertions.
backend/src/test/kotlin/org/loculus/backend/controller/submission/SubmitExternalMetadataEndpointTest.kt Updates 422 assertions.
backend/src/test/kotlin/org/loculus/backend/controller/submission/SubmitEndpointTest.kt Updates 422 assertions.
backend/src/test/kotlin/org/loculus/backend/controller/submission/SubmitEndpointFileSharingTest.kt Updates 422 assertions.
backend/src/test/kotlin/org/loculus/backend/controller/submission/SubmitEditedSequenceEntryVersionEndpointTest.kt Updates 422 assertions.
backend/src/test/kotlin/org/loculus/backend/controller/submission/RevokeEndpointTest.kt Updates 422 assertions.
backend/src/test/kotlin/org/loculus/backend/controller/submission/ReviseEndpointTest.kt Updates 422 assertions.
backend/src/test/kotlin/org/loculus/backend/controller/submission/GetSubmittedMetadataEndpointTest.kt Updates 422 assertions.
backend/src/test/kotlin/org/loculus/backend/controller/submission/GetDataToEditEndpointTest.kt Updates 422 assertions.
backend/src/test/kotlin/org/loculus/backend/controller/submission/DeleteSequencesEndpointTest.kt Updates 422 assertions.
backend/src/test/kotlin/org/loculus/backend/controller/submission/ApproveProcessedDataEndpointTest.kt Updates 422 assertions.
backend/src/test/kotlin/org/loculus/backend/controller/seqsetcitations/SeqSetValidationEndpointsTest.kt Updates 422 assertions.
backend/src/test/kotlin/org/loculus/backend/controller/seqsetcitations/SeqSetEndpointsTest.kt Updates 422 assertions.
backend/src/test/kotlin/org/loculus/backend/controller/seqsetcitations/CitationEndpointsTest.kt Updates 422 assertions.
backend/src/test/kotlin/org/loculus/backend/controller/files/CompleteMultipartUploadEndpointTest.kt Updates multipart error assertions.
backend/src/test/kotlin/org/loculus/backend/controller/ExceptionHandlerTest.kt Verifies the updated 422 title and matcher.
backend/src/test/kotlin/org/loculus/backend/controller/debug/DeleteAllSequenceDataEndpointTest.kt Updates processing-pipeline error assertions.
backend/src/test/kotlin/org/loculus/backend/controller/datauseterms/DataUseTermsControllerTest.kt Updates data-use-term error assertions.
backend/src/main/kotlin/org/loculus/backend/controller/SubmissionController.kt Uses the new 422 status constant for metrics.
backend/src/main/kotlin/org/loculus/backend/controller/ExceptionHandler.kt Uses the new 422 status constant and title.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@corneliusroemer corneliusroemer added review please PR waiting for final review and removed website Tasks related to the web application labels Aug 24, 2026
@anna-parker anna-parker added the preview Triggers a deployment to argocd label Aug 24, 2026
@tombch

tombch commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator

I had a look and there is still references in the backend to the UnprocessableEntityException, and tests reference unprocessable entity and unprocessableEntity - is the idea to have a minimal diff but fix the deprecation warnings?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend related to the loculus backend component preview Triggers a deployment to argocd review please PR waiting for final review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants