FAILURE MAP
← Case archive

FA-196 / Serialization / Open access

Line splitting removes a quoted CSV line break · case 01

A quoted multiline field is either split into records or silently concatenated without its newline.

Verified by executionVariant 1 · 8 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

Physical line splitting happens before a CSV-aware reader can preserve quoted line breaks.

VERIFIED REPAIR

Give the CSV parser the original text stream with newline translation disabled.

Unsuccessful approach: Using a CSV reader after splitlines understands quotes but has already discarded the embedded line endings.

Case contract

Read comma-delimited CSV using double-quote escaping and strict parser mode. Preserve embedded CR/LF characters within quoted fields, empty fields, and blank records; return None for parser errors.

Why this case matters

CSV records can span physical lines. Correct quote handling is not enough if the input preparation already removed information.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import csv
import io
N = 1
observations = []
def solve(text):
    return [line.split(',') for line in text.splitlines()]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
value = 'row' * N
check('embedded LF preserved', solve('"' + value + '\nnext",z\r\n'), [[value + '\nnext', 'z']])
check('embedded CRLF preserved', solve('"a\r\nb",' + str(N) + '\r\n'), [['a\r\nb', str(N)]])
check('quoted comma is field content', solve('"a,b",c\n'), [['a,b', 'c']])
check('doubled quote decoded', solve('"a""b",c\n'), [['a"b', 'c']])
check('trailing empty field', solve(value + ',\n'), [[value, '']])
check('blank records stay blank records', solve('\n' + value + '\n'), [[], [value]])
check('empty input', solve(''), [])
check('unterminated quoted field rejected', solve('"open,' + value), None)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
embedded LF preserved[['"row'], ['next"', 'z']][['row\nnext', 'z']]Failed
embedded CRLF preserved[['"a'], ['b"', '1']][['a\r\nb', '1']]Failed
quoted comma is field content[['"a', 'b"', 'c']][['a,b', 'c']]Failed
doubled quote decoded[['"a""b"', 'c']][['a"b', 'c']]Failed
trailing empty field[['row', '']][['row', '']]Passed
blank records stay blank records[[''], ['row']][[], ['row']]Failed
empty input[][]Passed
unterminated quoted field rejected[['"open', 'row']]NoneFailed

SHA-256 / d1ba522b69225e593ddbae8dbf92ca23a588432f2c30d622f7cb515956e532e4

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import csv
import io
N = 1
observations = []
def solve(text):
    try:
        return list(csv.reader(text.splitlines(), strict=True))
    except csv.Error:
        return None
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
value = 'row' * N
check('embedded LF preserved', solve('"' + value + '\nnext",z\r\n'), [[value + '\nnext', 'z']])
check('embedded CRLF preserved', solve('"a\r\nb",' + str(N) + '\r\n'), [['a\r\nb', str(N)]])
check('quoted comma is field content', solve('"a,b",c\n'), [['a,b', 'c']])
check('doubled quote decoded', solve('"a""b",c\n'), [['a"b', 'c']])
check('trailing empty field', solve(value + ',\n'), [[value, '']])
check('blank records stay blank records', solve('\n' + value + '\n'), [[], [value]])
check('empty input', solve(''), [])
check('unterminated quoted field rejected', solve('"open,' + value), None)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
embedded LF preserved[['rownext', 'z']][['row\nnext', 'z']]Failed
embedded CRLF preserved[['ab', '1']][['a\r\nb', '1']]Failed
quoted comma is field content[['a,b', 'c']][['a,b', 'c']]Passed
doubled quote decoded[['a"b', 'c']][['a"b', 'c']]Passed
trailing empty field[['row', '']][['row', '']]Passed
blank records stay blank records[[], ['row']][[], ['row']]Passed
empty input[][]Passed
unterminated quoted field rejectedNoneNonePassed

SHA-256 / ab4a610ee411cb9183709092eb5c8220a4cf109ccd5688ab73defee611c7e066

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
import csv
import io
N = 1
observations = []
def solve(text):
    try:
        return list(csv.reader(io.StringIO(text, newline=''), strict=True))
    except csv.Error:
        return None
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
value = 'row' * N
check('embedded LF preserved', solve('"' + value + '\nnext",z\r\n'), [[value + '\nnext', 'z']])
check('embedded CRLF preserved', solve('"a\r\nb",' + str(N) + '\r\n'), [['a\r\nb', str(N)]])
check('quoted comma is field content', solve('"a,b",c\n'), [['a,b', 'c']])
check('doubled quote decoded', solve('"a""b",c\n'), [['a"b', 'c']])
check('trailing empty field', solve(value + ',\n'), [[value, '']])
check('blank records stay blank records', solve('\n' + value + '\n'), [[], [value]])
check('empty input', solve(''), [])
check('unterminated quoted field rejected', solve('"open,' + value), None)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
embedded LF preserved[['row\nnext', 'z']][['row\nnext', 'z']]Passed
embedded CRLF preserved[['a\r\nb', '1']][['a\r\nb', '1']]Passed
quoted comma is field content[['a,b', 'c']][['a,b', 'c']]Passed
doubled quote decoded[['a"b', 'c']][['a"b', 'c']]Passed
trailing empty field[['row', '']][['row', '']]Passed
blank records stay blank records[[], ['row']][[], ['row']]Passed
empty input[][]Passed
unterminated quoted field rejectedNoneNonePassed

SHA-256 / 49ccf1e81b6e55e27b51bc9c38d506a8539a44beedcd6df811d71adbb34646f4

Verification & scope

This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.

Observations recorded using Python 3.12.14 at 2026-09-29T14:36:51.028600+00:00.

Case digest / 27b2330995e058685c30369b02e95a5dfb0823bb85e745da7aae54f3c39dd4ab