Skip to content

Line handler splits output on U+2028, U+2029, NEL (U+0085) and form feed, breaking NDJSON records that OutputDataReceived/ReadLine keep whole #133

Closed

Description

@matt-edmondson

What's wrong

LineOutputHandler ends a line on any of LF, CR, CRLF, NEL (U+0085), LS (U+2028), PS (U+2029) and form feed:

private static bool IsLineBreak(char c) => c is '\n' or '\u0085' or '\u2028' or '\u2029' or '\f';

private static bool IsLineBreak(char c) => c is '\n' or '\u0085' or '
' or '
' or '\f';

(used from ProcessDataByLine, lines 139–144). This set came from the original data.ReplaceLineEndings() implementation and was carried over in da03a26 (#85) for compatibility with that code. However Process.OutputDataReceived, StreamReader.ReadLine and essentially every line-oriented tool treat only CR, LF and CRLF as line breaks. No test covers the extra characters.

Why it matters

Those characters are allowed raw inside JSON strings. JSON.stringify, jq -c and Python's json.dumps(..., ensure_ascii=False) all emit U+2028/U+2029 unescaped. So a tool that prints NDJSON (one object per line) gets its records cut in half, and a caller that parses each delivered line as JSON throws.

Reproduced on Linux, net10.0, at current main:

command: sh -c "printf '{\"a\":\"x<U+2028>y\"}\n{\"b\":\"p\fq\"}\n'"
LineOutputHandler      -> 4 lines: {"a":"x | y"} | {"b":"p | q"}
Process.OutputDataReceived -> 2 lines

Running with Encoding.Latin1 has the same effect: every 0x85 byte becomes U+0085 and ends the line.

Suggested fix / acceptance criteria

Activity

  1. matt-edmondson commented on Nov 2, 2026

    @matt-edmondson
    ContributorAuthor

    Triage


    Generated by Claude Code

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

Metadata

Metadata

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions