Skip to content

fix(backend): clarify duplicate ID errors - #7309

Open
clonder wants to merge 1 commit into
mainfrom
fix/7106-duplicate-upload-id-errors
Open

fix(backend): clarify duplicate ID errors#7309
clonder wants to merge 1 commit into
mainfrom
fix/7106-duplicate-upload-id-errors

Conversation

@clonder

@clonder clonder commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Shows duplicate IDs instead of raw Postgres errors, using one helper for submission and revision.

Closes #7106

PR Checklist

  • All necessary documentation has been adapted.
    • no docs changes needed
  • The implemented feature is covered by appropriate, automated tests.
    • submission and revision endpoint tests
  • Any manual testing that has been done is documented (i.e. what exactly was tested?)
    • ran ./gradlew test ktlintCheck locally, 638 tests passed and 1 skipped

🚀 Preview: Add preview label to enable

@claude claude Bot added the backend related to the loculus backend component label Sep 11, 2026
@clonder
clonder marked this pull request as ready for review September 11, 2026 09:57
@claude

claude Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Claude finished @clonder's task in 3m 28s —— View job


Code review

  • Read the PR diff and surrounding code
  • Check DB constraints the parser relies on
  • Check for other consumers of the old error strings
  • Review test coverage
  • Post inline comments

Good change overall. Leaking ${e.cause?.cause} into a user-facing 422 was the actual bug in #7106, and routing everything through one parser fixes submission, revision and the FASTA path together. Two details I specifically checked and can confirm are correct:

  • The regex's (upload_id, X) shape holds for all three constraints that can fire here — V1__init.sql:144, V1.16__unique_loculus_accession_for_revisions.sql:3, V1.22__refactor_aux_tables.sql:20.
  • Postgres does not quote or escape values in the Key (…)=(…) detail, so the [^,]+ / greedy (.+) split is the right way to handle IDs containing commas and parens. The SAMPLE,C(1) test cases pin that well — nice.
  • No website, e2e or docs code matches on the old message strings, so the wording change is safe.

Four inline comments, none blocking:

Where Point
UploadDatabaseService.kt:117-124 takeUnless drops the stack trace on unparseable unique violations — the one case that needs it. e.message is gone from the log too.
DuplicateRecordId.kt:9-13 Regex depends on English lc_messages and on column ordering; both degrade silently and neither degraded path is tested. A DB-free unit test over the parser would pin it.
DuplicateRecordId.kt:16-21 SQLException.iterator() already walks the cause chain, so the outer generateSequence { it.cause } is redundant.
SubmitModel.kt:340-343 Both call sites discard DuplicateRecordId.field and hardcode the label; the ": $it" suffix is duplicated.

One note on the changed error semantics that is worth a conscious decision rather than a code change: the revision path reports one duplicate (whichever constraint Postgres hits first), where the removed extractDuplicateColumns built a combined message across accession and submission_id. In practice only one constraint fires per statement so this isn't a regression, but a file with both kinds of duplicate now needs two round trips to surface both. The "at least one" wording already sets that expectation, so I'd leave it.

I did not run the test suite — the diff is message-shape only and the assertions are exact-match, so the local ./gradlew test ktlintCheck run reported in the description covers it.
· branch fix/7106-duplicate-upload-id-errors

Comment thread backend/src/main/kotlin/org/loculus/backend/model/SubmitModel.kt
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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Duplicate submissionId error shows users the raw Postgres exception with table name, constraint and internal UUID

1 participant