Skip to content

fix(output): propagate serialization and write failures - #232

Open
Gautam Sharma (GautamSharma99) wants to merge 1 commit into
langchain-ai:mainfrom
GautamSharma99:fix/output-write-errors-224
Open

fix(output): propagate serialization and write failures#232
Gautam Sharma (GautamSharma99) wants to merge 1 commit into
langchain-ai:mainfrom
GautamSharma99:fix/output-write-errors-224

Conversation

@GautamSharma99

Copy link
Copy Markdown
Contributor

Summary

  • make JSON, JSONL, and pretty JSON output helpers return serialization and I/O errors
  • check short writes, file creation, writes, explicit closes, and status-output writes
  • emit file-success status only after the data write and close complete successfully
  • route every command output call through checked wrappers so failures terminate the CLI non-zero
  • fix trace export's separate JSONL implementation to check marshal, write, short-write, and close failures

Closes #224.

Problem

The shared output helpers previously treated several failure modes as success:

  • OutputJSON printed marshal/write errors but returned normally
  • OutputJSONL ignored marshal, write, newline, and deferred-close errors
  • PrintOutput ignored marshal and os.WriteFile errors entirely
  • trace export had a second JSONL loop with unchecked marshal/write/close calls

In the JSONL path, the CLI printed {"status":"written"} even if an earlier write or the final close failed. Commands therefore exited with status 0 after producing a missing or truncated export.

Implementation

Error-returning output APIs

The following internal output functions now return error:

OutputJSON(data, path) error
OutputJSONL(items, path) error
PrintOutput(data, format, path) error

Errors include operation and path context while retaining the underlying error for errors.Is/errors.As.

JSON output now checks:

  • json.MarshalIndent
  • file writes
  • stdout writes and short writes
  • status writes

JSONL output now checks:

  • file creation
  • each item marshal
  • each complete line write, including short writes
  • explicit file close
  • stdout and status writes

On a write failure, the file is closed best-effort and no success status is printed. On normal completion, close is performed and checked before success is reported.

Command propagation

All command call sites now use three checked command-layer wrappers. Those wrappers feed output failures through the CLI's existing ExitErrorf policy, producing an actionable stderr error and a non-zero process exit. This keeps existing command callbacks and successful output schemas unchanged while ensuring no helper error is ignored.

Most command-file changes in this PR are the mechanical replacement of:

output.OutputJSON(...)

with:

outputJSON(...)

The wrappers are the only command-layer callers of the error-returning output APIs.

Trace export

Trace export writes one JSONL file per trace without using the shared JSONL helper because it has per-trace extraction behavior. Its loop now:

  • checks every marshal
  • writes each JSON object and newline as one checked operation
  • detects io.ErrShortWrite
  • closes the file immediately on failure
  • checks the successful final close before incrementing the exported count

The final count can no longer include a trace whose file failed to finish writing.

Behavior

Successful output and status payloads remain unchanged.

On failure, commands now behave like:

$ langsmith ... --output /missing/path/results.json
writing output: writing /missing/path/results.json: ...
$ echo $?
1

No "status": "written" line is emitted for failed writes or failed closes.

Tests

Added deterministic coverage for:

  • unsupported values causing JSON marshal failure
  • invalid/unwritable output paths
  • pretty-output file failures
  • partial writes returning io.ErrShortWrite
  • explicit writer failures after file creation
  • close failures
  • closing a writer after a write failure
  • suppression of success status after write or close failure
  • subprocess-level confirmation that a command-layer output failure exits non-zero and names the failed path

Existing success tests now assert that the output helpers return nil.

Local verification:

  • focused output failure tests
  • command subprocess exit test
  • go test ./...
  • go test -race ./...
  • go vet ./...
  • make build
  • git diff --check

make lint was not available locally because golangci-lint is not installed.

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.

output and export helpers report success after write failures

1 participant