Skip to content

Bulk record upload inserts rows that already exist or repeat within the file, silently duplicating data #1884

Open

Description

@gdevenyi

Problem

POST /instrument-records/upload (InstrumentRecordsService.upload) inserts every row it receives. It does not check:

  • for rows repeated inside the same request, or
  • for rows that already exist (same subject, instrument, date and data).

So if a user uploads the same CSV again, or the browser sends the request again, all data is silently doubled. Nothing tells the user that the rows were already present.

Observed

A production instance (v2.5.2) holds 28,177 MOUSE_WEIGHT_FORM records that contain only 1,317 unique measurements for 402 subjects:

  • 7 upload batches over two days (2024-12-04 and 2025-01-07) put the same file in again, both in a group and with no group.
  • Inside one batch of 3,520 rows, 1,100 measurements occur 3 times, a few seconds apart. Either the CSV had repeated rows, or the request was sent again.
  • Each duplicate also has its own session (see the companion issue about deleting sessions).

About 38 smaller groups of exact duplicates come from forms submitted twice a few minutes apart.

Proposal (needs decision)

  • Server: before insert, find the existing records that match (subjectId, instrumentId, date, canonical JSON of data) and the matching rows inside the batch. Then either reject the request with a 409 that lists them, or skip them and return a count of created and skipped rows. A content hash stored on the record would make this an indexed lookup.
  • Web: show "N rows already exist, M rows repeated in the file" before the submit, with an explicit choice. The current page hides the form while the upload runs, but the server must not depend on the client for this.
  • The single-record POST /instrument-records may need the same guard against a double submit (a short time window, or an idempotency key).

Each change needs a unit test and an e2e test.

Activity

  1. added
    BugType: existing behavior is wrong
    Priority: HighSignificant or frequently hit user impact; target the next release or two
    Difficulty: MediumStraightforward change, about a day or less
    Area: APIapps/api (NestJS backend, Prisma models, CASL permissions)
    Area: Webapps/web (clinician-facing React SPA)
    Needs DecisionWell-defined, but blocked on a maintainer decision about direction or design
    on Nov 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Area: APIapps/api (NestJS backend, Prisma models, CASL permissions)Area: Webapps/web (clinician-facing React SPA)BugType: existing behavior is wrongDifficulty: MediumStraightforward change, about a day or lessNeeds DecisionWell-defined, but blocked on a maintainer decision about direction or designPriority: HighSignificant or frequently hit user impact; target the next release or two

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions