Repository navigation
CSV export returns 500 when a column is named accession or the variant is deleted mid-request #844
Description
Summary
Two CSV export cases fail with a 500 error and a Slack alert, even though neither is a server fault. If a score set has a score or count column named accession, every download of it fails. If a variant is deleted while someone is downloading it, the request fails instead of returning 404. This issue makes both return proper responses.
Column named accession
Un-namespaced exports (GET /score-sets/{urn}/scores and GET /score-sets/{urn}/counts) put the built-in accession column and the investigator's columns under bare headers. When an investigator's column is also named accession, assemble_csv_headers (src/mavedb/lib/csv/columns.py) finds two identical headers and raises ValueError. Nothing at upload time stops the column being created.
accession is the only built-in name that can collide. The other built-in columns (hgvs_nt, hgvs_splice, hgvs_pro) are the variant columns themselves: upload removes them from the score and count data (create_variants_data in src/mavedb/lib/score_sets.py), so they never reach the exports as investigator columns.
- Export: in un-namespaced output, when an investigator's column collides with a built-in one, put its namespace in front (
scores.accession,counts.accession) and leave the built-in column as is. Headers and row keys both come from_format_column_key, so make the decision once and use it for both. Document the rule inassemble_csv_headers's docstring. - Upload: reject a score or count column named
accessioninvalidate_column_names(src/mavedb/lib/validation/dataframe/dataframe.py). Match case-insensitively, as the existing duplicate-name check does.
Variant deleted mid-request
get_variant_csv and available_variant_csv_namespaces (src/mavedb/lib/csv/variant.py) raise ValueError when the variant doesn't exist. The routers check that the variant exists first, so this only happens when the variant is deleted between the check and the lib call. Raise NonexistentIdentifierError (src/mavedb/lib/exceptions.py) instead. It already has a handler in server_main.py that returns 404.
Acceptance criteria
-
GET /score-sets/{urn}/scoresfor a score set with a score column namedaccessionreturns 200, with that column headedscores.accession. -
GET /score-sets/{urn}/countsfor a score set with a count column namedaccessionreturns 200, with that column headedcounts.accession. - Uploading a score or count column named
accession, in any letter case, is rejected with a validation error. - Uploads with
hgvs_nt,hgvs_spliceandhgvs_procolumns are still accepted. - When
get_variant_csvoravailable_variant_csv_namespacescan't find the variant,GET /variants/{urn}/csvandGET /variants/{urn}/csv-namespacesreturn 404. - Nothing in
src/mavedb/lib/csv/raises a bareValueErrorto a router for user data or a missing variant.
Background
ValueErrorhas no registered handler. It falls through to the catch-all inserver_main.py, which returns{"detail": "Internal server error"}with a correlation id and callssend_slack_error.- The export corpus sweep doesn't catch the collision:
export_sweep._compose_score_set_csvbuilds its CSVs withnamespaced=True, which always adds the prefix. - Prefixing at export, rather than renaming stored data, keeps existing score sets downloadable. Only score sets that already have a colliding column get a different header.
- A column named
Accessiondoesn't collide today, because exports keep the uploaded case. Upload rejects it anyway so the rule matches the case-insensitive duplicate check.
Activity
[-]CSV export raises bare ValueError, which reaches the caller as a 500[/-][+]CSV export returns 500 when a column is named `accession` or the variant is deleted mid-request[/+]