Skip to content

CSVDocumentCleaner deletes a row that says N/A, and both CSV components empty those cells #12784

Description

@L4XB

Describe the bug

CSVDocumentCleaner deletes a row whose cells say N/A, and both it and CSVDocumentSplitter empty any cell holding one of pandas' default missing-value strings.

pd.read_csv treats the literal strings N/A, NA, n/a, NULL, None, NaN and nan as missing values. Neither component passes keep_default_na=False, and dtype=object does not change it — the string is gone before the dtype is applied. CSVDocumentCleaner then runs dropna(how="all") over those rows, so a row that says "not applicable" in every column is treated as an empty row and removed.

Error message

None. No error, no warning — the document simply comes back smaller.

Expected behavior

A cell that says N/A is a cell with content. N/A is how a person writes "not applicable" and NULL is what a database export writes, so those cells usually carry the answer someone would ask the document for. They should survive cleaning and splitting; only genuinely empty cells should count as empty.

Additional context

Measured on main (7476cef):

from haystack import Document
from haystack.components.preprocessors.csv_document_cleaner import CSVDocumentCleaner

# 1. a row that says N/A everywhere is deleted
csv = "Code,Status\nA1,ok\nN/A,N/A\nA3,ok\n"
CSVDocumentCleaner().run(documents=[Document(content=csv)])["documents"][0].content
# -> 'Code,Status\nA1,ok\nA3,ok\n'     the middle row is gone

# 2. a column of statuses is emptied
csv = "Code,Status,Note\nA1,N/A,keep\nA2,NULL,keep\nA3,NA,keep\n"
CSVDocumentCleaner().run(documents=[Document(content=csv)])["documents"][0].content
# -> 'Code,Status,Note\nA1,,keep\nA2,,keep\nA3,,keep\n'

CSVDocumentSplitter produces the same emptied content for case 2.

The fix is one merged default in each component, keeping the caller's override intact:

# cleaner
df = pd.read_csv(StringIO(document.content), header=None, dtype=object, keep_default_na=False)

# splitter
resolved_read_csv_kwargs = {
    "header": None, "skip_blank_lines": False, "dtype": object,
    "keep_default_na": False, **self.read_csv_kwargs,
}

A genuinely empty cell is unaffected — keep_default_na governs only the string list, not real blanks — so remove_empty_rows / remove_empty_columns keep doing their job.

I have this reproduced with tests and would normally open the PR, but the flood guard on my last PR asks me to hold off until the first two of my open ones are reviewed, so this is the report instead. Say the word and I will send it.

To Reproduce

The two snippets above, against main.

FAQ Check

System:

  • OS: macOS
  • Haystack version: main at 7476cef
  • Reproduced with the installed pandas from the dev extras

Activity

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions