[GH-ISSUE #7441] [Bug] demangle-swift --json indents argument errors on piped and redirected stdout #4444

Closed
opened 2026-10-31 00:49:51 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @coygeek on GitHub (Oct 27, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/7441

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

CLI

Observed behavior

With required arguments omitted, the built CLI's demangle-swift command rejects the request with VALIDATION_ERROR and exit 1, but --json writes indented output to a capture pipe and a regular file. Both destinations receive a complete 22-line, 595-byte document; compact serialization of that same value takes 463 bytes.

Reproduction

  1. Use the baseline source checkout with its locked dependencies installed and compiled runtime available, named rea. Start in an empty working directory beside that checkout, with Node 24.22.1 on PATH. No target fixture is needed.
  2. Run this script. It creates an isolated HOME inline, invokes the public entrypoint twice with stdout captured through a pipe and once redirected to error.json, and parses every resulting document.
python3 -I - <<'PYREPRO'
import json, os, subprocess
from pathlib import Path

Path("home").mkdir(exist_ok=True)
env = dict(os.environ, HOME=str(Path("home").resolve()))
command = ["node", "../rea/scripts/rea.mjs", "demangle-swift", "--json"]
outputs = []
for label in ("pipe-1", "pipe-2", "redirected"):
    if label == "redirected":
        with open("error.json", "wb") as output:
            result = subprocess.run(command, env=env, stdout=output, stderr=subprocess.PIPE, timeout=30)
        raw = Path("error.json").read_bytes()
    else:
        result = subprocess.run(command, env=env, capture_output=True, timeout=30)
        raw = result.stdout
    value = json.loads(raw)
    compact = json.dumps(value, separators=(",", ":")) + "\n"
    print(f"{label}: exit={result.returncode} lines={len(raw.splitlines())} bytes={len(raw)} stderr={len(result.stderr)} code={value['code']} compact_bytes={len(compact.encode())}")
    outputs.append(raw)
print("pipe/file bytes identical:", len(set(outputs)) == 1)
print("\n".join(outputs[0].decode().splitlines()[:3]))
PYREPRO
  1. Observe this output. The exact script reproduced indentation in all three invocations; an earlier independent set of two pipe captures and one file redirect reproduced it too, for six failures in six attempts.
pipe-1: exit=1 lines=22 bytes=595 stderr=0 code=VALIDATION_ERROR compact_bytes=463
pipe-2: exit=1 lines=22 bytes=595 stderr=0 code=VALIDATION_ERROR compact_bytes=463
redirected: exit=1 lines=22 bytes=595 stderr=0 code=VALIDATION_ERROR compact_bytes=463
pipe/file bytes identical: True
{
  "code": "VALIDATION_ERROR",
  "message": "REA could not read the command arguments. Check the named argument and its expected type, then try again.",

Expected behavior

The general "Output and exit status" section of docs/cli.md states: "--json is indented on a terminal and compact when piped or redirected, which keeps large results smaller for agents and scripts; pipe through jq . for indented files." The statement has no exception for command-argument diagnostics. These nonterminal invocations should emit compact JSON while preserving the error value and exit status.

Impact and scope

Each omitted-argument invocation added 132 whitespace bytes. The diagnostic remains complete and parseable, and its correction fields and failure status remain available. No downstream parsing failure, token cost, performance effect or data loss was demonstrated. Observed scope is the omitted-argument case above; one unknown-command control also returned indented JSON, while one typed operation-failure control returned compact JSON. Other commands and platforms remain untested.

REA version

6.8.0 (source commit a905a71e31)

Runtime and platform

Node 24.22.1; macOS 27.0.1 arm64.

Target and artifact context

Not applicable: argument validation rejects the invocation before target access, without an analysis provider or external service.

Interface

CLI

Earliest failure stage

Transport or result projection

Relevant output or evidence

Observed through the packaged source entrypoint, with redirected HOME and subprocess capture or regular-file stdout. The document starts with an opening brace on its own line and two-space-indented code and message fields, as shown above. All six primary invocations exited 1 with empty stderr and complete JSON; the exact report script confirmed byte equality across its pipe/file captures. The expected contract is docs/cli.md:954-963. The destination-aware writer is src/cli/jsonOutput.ts:14-22 and :34-35; ordinary command results use it at src/cli/cliResultOutput.ts:510-518.

Typed outcome or recovery expected

Keep VALIDATION_ERROR, all correction fields and exit 1, with compact serialization on nonterminal stdout. No change to diagnostic content or JSONL framing is needed.

Analysis or suspected cause

Source-only (not executed as an instrumented trace): src/cli/cliResultOutput.ts:68-111 wraps command dispatch results, while src/cli/argumentErrors.ts:12-25 rethrows parser validation errors with revised guidance. The launcher forwards SDK output at scripts/rea.mjs:139-150. SDK capture is restricted to JSONL at src/cli/cliResultOutput.ts:229-234, so ordinary JSON diagnostics bypass REA's destination-aware writer. The installed formatter at node_modules/incur/dist/Formatter.js:8-19 unconditionally uses two-space indentation for JSON. These source paths explain the observed representation difference.

Additional context

Related (closed):

The npm registry reports 6.8.0 as the latest published rea-agents version. No last-known-good version was established.

Originally created by @coygeek on GitHub (Oct 27, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/7441 ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area CLI ### Observed behavior With required arguments omitted, the built CLI's demangle-swift command rejects the request with VALIDATION_ERROR and exit 1, but --json writes indented output to a capture pipe and a regular file. Both destinations receive a complete 22-line, 595-byte document; compact serialization of that same value takes 463 bytes. ### Reproduction 1. Use the baseline source checkout with its locked dependencies installed and compiled runtime available, named rea. Start in an empty working directory beside that checkout, with Node 24.22.1 on PATH. No target fixture is needed. 2. Run this script. It creates an isolated HOME inline, invokes the public entrypoint twice with stdout captured through a pipe and once redirected to error.json, and parses every resulting document. ```sh python3 -I - <<'PYREPRO' import json, os, subprocess from pathlib import Path Path("home").mkdir(exist_ok=True) env = dict(os.environ, HOME=str(Path("home").resolve())) command = ["node", "../rea/scripts/rea.mjs", "demangle-swift", "--json"] outputs = [] for label in ("pipe-1", "pipe-2", "redirected"): if label == "redirected": with open("error.json", "wb") as output: result = subprocess.run(command, env=env, stdout=output, stderr=subprocess.PIPE, timeout=30) raw = Path("error.json").read_bytes() else: result = subprocess.run(command, env=env, capture_output=True, timeout=30) raw = result.stdout value = json.loads(raw) compact = json.dumps(value, separators=(",", ":")) + "\n" print(f"{label}: exit={result.returncode} lines={len(raw.splitlines())} bytes={len(raw)} stderr={len(result.stderr)} code={value['code']} compact_bytes={len(compact.encode())}") outputs.append(raw) print("pipe/file bytes identical:", len(set(outputs)) == 1) print("\n".join(outputs[0].decode().splitlines()[:3])) PYREPRO ``` 3. Observe this output. The exact script reproduced indentation in all three invocations; an earlier independent set of two pipe captures and one file redirect reproduced it too, for six failures in six attempts. ```text pipe-1: exit=1 lines=22 bytes=595 stderr=0 code=VALIDATION_ERROR compact_bytes=463 pipe-2: exit=1 lines=22 bytes=595 stderr=0 code=VALIDATION_ERROR compact_bytes=463 redirected: exit=1 lines=22 bytes=595 stderr=0 code=VALIDATION_ERROR compact_bytes=463 pipe/file bytes identical: True { "code": "VALIDATION_ERROR", "message": "REA could not read the command arguments. Check the named argument and its expected type, then try again.", ``` ### Expected behavior The general "Output and exit status" section of docs/cli.md states: "--json is indented on a terminal and compact when piped or redirected, which keeps large results smaller for agents and scripts; pipe through jq . for indented files." The statement has no exception for command-argument diagnostics. These nonterminal invocations should emit compact JSON while preserving the error value and exit status. ### Impact and scope Each omitted-argument invocation added 132 whitespace bytes. The diagnostic remains complete and parseable, and its correction fields and failure status remain available. No downstream parsing failure, token cost, performance effect or data loss was demonstrated. Observed scope is the omitted-argument case above; one unknown-command control also returned indented JSON, while one typed operation-failure control returned compact JSON. Other commands and platforms remain untested. ### REA version 6.8.0 (source commit a905a71e31f71457cb21fd056b234f872126974e) ### Runtime and platform Node 24.22.1; macOS 27.0.1 arm64. ### Target and artifact context Not applicable: argument validation rejects the invocation before target access, without an analysis provider or external service. ### Interface CLI ### Earliest failure stage Transport or result projection ### Relevant output or evidence Observed through the packaged source entrypoint, with redirected HOME and subprocess capture or regular-file stdout. The document starts with an opening brace on its own line and two-space-indented code and message fields, as shown above. All six primary invocations exited 1 with empty stderr and complete JSON; the exact report script confirmed byte equality across its pipe/file captures. The expected contract is docs/cli.md:954-963. The destination-aware writer is src/cli/jsonOutput.ts:14-22 and :34-35; ordinary command results use it at src/cli/cliResultOutput.ts:510-518. ### Typed outcome or recovery expected Keep VALIDATION_ERROR, all correction fields and exit 1, with compact serialization on nonterminal stdout. No change to diagnostic content or JSONL framing is needed. ### Analysis or suspected cause Source-only (not executed as an instrumented trace): src/cli/cliResultOutput.ts:68-111 wraps command dispatch results, while src/cli/argumentErrors.ts:12-25 rethrows parser validation errors with revised guidance. The launcher forwards SDK output at scripts/rea.mjs:139-150. SDK capture is restricted to JSONL at src/cli/cliResultOutput.ts:229-234, so ordinary JSON diagnostics bypass REA's destination-aware writer. The installed formatter at node_modules/incur/dist/Formatter.js:8-19 unconditionally uses two-space indentation for JSON. These source paths explain the observed representation difference. ### Additional context Related (closed): - https://github.com/morluto/rea/issues/5435 fixed compact JSON for MCP doctor reports; ordinary-command parser diagnostics still reproduce the same whitespace-contract violation on this baseline. - https://github.com/morluto/rea/issues/3894 fixed truncated pipe output; this baseline's complete and parseable diagnostic still violates the independent compactness promise. The npm registry reports 6.8.0 as the latest published rea-agents version. No last-known-good version was established.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#4444
No description provided.