Skip to content

fix: apply transformHeader only once per header in streaming/chunked parsing - #1130

Merged
pokoli merged 1 commit into
mholt:masterfrom
xianjianlf2:fix/transformheader-once-streaming-1083
Aug 24, 2026
Merged

fix: apply transformHeader only once per header in streaming/chunked parsing#1130
pokoli merged 1 commit into
mholt:masterfrom
xianjianlf2:fix/transformheader-once-streaming-1083

Conversation

@xianjianlf2

Copy link
Copy Markdown
Contributor

Summary

Fixes #1083

When header: true is combined with a transformHeader callback, the callback is currently invoked twice per header column. For non-idempotent transforms (e.g. appending a suffix, mapping display names to keys), this corrupts the resulting field names, and since the duplicate-header renaming logic landed, users also see spurious "Duplicate headers found and renamed" warnings and _1-suffixed columns. Multiple users on #1083 report this as a regression from 5.4.1 to 5.5.x, affecting both streaming/chunked and plain parsing.

Root cause

Two code paths each apply the header processing:

  1. The core Parser's returnable() BOM-strips, applies transformHeader, and de-duplicates the header row in place (added in Refactor header renaming logic to adress #1052, #1007 #1058 for duplicate-header renaming).
  2. ParserHandle.fillHeaderFields()'s addHeader() then re-applies stripBom and transformHeader to those already-transformed values when copying them into _fields.

#1086 ("Only attempt to parse headers once") added a headerParsed guard, but that only stops returnable() from re-running across chunks — the double application between returnable() and fillHeaderFields() remained, so #1083 stayed reproducible after it was merged.

Fix

addHeader() no longer re-applies stripBom/transformHeader; it simply collects the values that returnable() has already processed. Header transformation now runs exactly once per column, matching the 5.4.1 behavior while keeping the duplicate-header renaming from #1058.

Tests

  • Added a test asserting transformHeader is called exactly once per header when parsing in chunks, with a non-idempotent transform (fails before this change: headers come out double-transformed).
  • Full suite passes locally: npm test (lint + node mocha + mocha-headless-chrome), 249 node / 251 browser tests passing.

transformHeader was invoked twice per header column: once by the core
Parser's returnable(), which transforms and de-duplicates the header row
in place, and again by ParserHandle.fillHeaderFields() when copying the
header into _fields. The second call additionally operated on the
already-transformed value, so a non-idempotent transformHeader corrupted
the field names (e.g. "Col_X" became "Col_X_X").

This is a regression: header transformation was correct in 5.4.1 and
broke in 5.5.x when the duplicate-header renaming logic (mholt#1058) added a
transformHeader call inside returnable() without removing the existing
one in fillHeaderFields(). A later fix (mholt#1086) added a headerParsed guard
but only stopped returnable() from re-running, leaving the double call
between the two functions in place.

Since returnable() already BOM-strips, transforms and de-duplicates the
header row in place, fillHeaderFields() now just collects the
already-processed values.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

transformHeader Called Multiple Times in Papa Parse v5.5.1

2 participants