Skip to content

Bulk assignment paste/CSV parse errors report a row number one lower than the line in the user's file #1644

Description

@joshunrau

When pasted or uploaded delimited text has a malformed line, parseDelimitedText reports a row number one lower than the row the user sees in their file. It passes Papa Parse's zero-based error.row through unchanged. Every other row-numbered error in the bulk remote assignment wizard counts the header as row 1, which is what BulkParseError.row documents. So the wizard's error list (Row N:) points the user at the line above the one that is actually broken, and a single file can get row numbers from both schemes depending on which check fails.

Where

  • apps/web/src/utils/bulk-assignments.ts:261, which passes the parser's row through as is:
    throw new BulkParseFailure(fatal.map((error) => ({ message: error.message, row: error.row })));
  • apps/web/src/utils/bulk-assignments.ts:68, where BulkParseError.row is documented as the "1-based index of the offending row as the user sees it in their file".
  • apps/web/src/utils/bulk-assignments.ts:339-340, where resolveSubjectIds uses index + 2, so the first data row is row 2.
  • apps/web/src/components/BulkRemoteAssignmentWizard/ErrorList.tsx:32-34 renders the number as Row ${error.row}:.

Reproduce

Paste this into the wizard (or call parseDelimitedText with it):

subjectId
"subject-1

The unterminated quote is on line 2 of the file.

  • Actual: { message: 'Quoted field unterminated', row: 1 }, shown as "Row 1: Quoted field unterminated".
  • Expected: row: 2.

The offset is the same further down. subjectId\na\nb\n"c has the bad quote on line 4, and Papa Parse reports row: 3.

Tests

apps/web/src/utils/__tests__/bulk-assignments.test.ts, test "should reject malformed quoting with the parser's error message". It currently asserts only the message, because a row number of 1 was deliberately left unpinned. When fixing, change it back to assert the full error, [{ message: 'Quoted field unterminated', row: 2 }].

Suggested fix

Map error.row to error.row + 1 when it is defined. Papa Parse's row counts the header line from zero, so this gives the same header-is-row-1 numbering that resolveSubjectIds uses.

Found while raising unit test coverage in #1632.

Activity

  1. added
    BugType: existing behavior is wrong
    Priority: LowNice to have, cosmetic or speculative
    Difficulty: LowIsolated change, about 2 hours or less
    Area: Webapps/web (clinician-facing React SPA)
    Good First IssueWell-scoped, low-risk and self-contained; a good entry point for a new contributor
    on Oct 5, 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: Webapps/web (clinician-facing React SPA)BugType: existing behavior is wrongDifficulty: LowIsolated change, about 2 hours or lessGood First IssueWell-scoped, low-risk and self-contained; a good entry point for a new contributorPriority: LowNice to have, cosmetic or speculative

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions