Propagate Connection.send errors in build-and-send#6
Conversation
There was a problem hiding this comment.
Build & Tests
Build: pass (CI green on macOS and Ubuntu). Tests: pass (all existing tests pass).
Findings
1. Resource leak on send error path (blocking)
http-client.carp:271-273 — When Connection.send fails, the function returns (Result.Error e) and conn (the owned Connection from line 265) goes out of scope without being closed. Connection wraps TcpStream/TlsStream, which are register-type without custom delete — Carp's auto-generated drop won't close the socket fd or free TLS resources. In the old code, conn was always returned to the caller who eventually closed it.
Fix:
(match (Connection.send &conn &(Request.str &req))
(Result.Success _) (Result.Success conn)
(Result.Error e) (do (Connection.close conn) (Result.Error e)))
2. Partial send is silently treated as success (pre-existing, not introduced by this PR)
Connection.send returns (Result Int String) where the Int is bytes sent. The (Result.Success _) arm discards this count, so a partial send (fewer bytes than the request) is silently treated as full success. The old ignore had the same behavior, so this isn't a regression — just noting it.
3. No tests for the error path
The test suite only tests connection-refused and invalid-URL errors. There are no tests exercising send failures (broken pipe, connection reset). Not blocking, but the leak in finding #1 would have been caught with one.
Verdict: revise
The concept is correct but the error path leaks the connection. One-line fix needed: close conn before returning the error.
|
Addressed carpentry-reviewer's finding #1 (resource leak on send error path):
Finding #2 (partial send treated as success) is pre-existing and not in scope for this PR. Finding #3 (no tests for error path) is noted but not blocking. |
There was a problem hiding this comment.
Build & Tests
Build: pass (first commit passed full CI pipeline including type-check, build, and tests). Tests: pass (all existing tests pass on both platforms for the first commit).
CI: failing — both macOS and Ubuntu fail at the format check step. carp-fmt --check rejects http-client.carp after commit 6e02dba (the Connection.close addition). The (do (Connection.close conn) (Result.Error e)) line likely exceeds the formatter's line-length threshold. Tests, lint, and build all pass — only formatting fails.
Prior feedback
Previous review identified the resource leak on the send error path (finding #1). The author addressed this correctly by adding (Connection.close conn) before returning the error. Finding #2 (partial send treated as success) was acknowledged as pre-existing and out of scope. Finding #3 (no error-path tests) was noted as non-blocking.
Findings
1. Formatting violation (blocking)
The second commit broke carp-fmt compliance. Run carp-fmt on http-client.carp and commit the result.
2. Code is correct
The fix is sound:
- Error propagation: replacing
(ignore (Connection.send ...))with amatchthat returns the error is correct. - Resource cleanup:
Connection.close conntakesconnby value (consuming ownership), matching the pattern used inrequest-stream-(lines 398, 409, 417, 423, 436). No use-after-move. let-do→let: Correct — the old code neededlet-dofor the imperativeignore/Result.Successsequence; the new code uses a singlematchexpression as theletbody.(do (Connection.close conn) (Result.Error e)):Connection.closereturns(),doreturns the last expression — types are fine.- No remaining
ignorecalls in the file.
Verdict: revise
One-line fix: run carp-fmt to resolve the formatting failure. The logic itself is correct and ready to merge once CI is green.
|
Addressed carpentry-reviewer's finding #1 from the second review (formatting violation): ran |
There was a problem hiding this comment.
Build & Tests
Build: pass — type-checks clean, CI green on macOS and Ubuntu.
Tests: pass — all existing tests pass on both platforms.
Prior feedback
Two prior review rounds:
- Resource leak (fixed):
Connection.close connadded before returning the error on the send failure path. Confirmed correct —closetakes ownership, matching the pattern used inrequest-stream-(lines 399, 410, 418, 424, 437). - Formatting violation (fixed):
carp-fmtrun on the file. CI now green. - Partial send as success (acknowledged, pre-existing): Out of scope, not a regression.
- No error-path tests (acknowledged, non-blocking): Noted but not required for this fix.
All four items properly resolved.
Findings
No new issues.
Verified:
- The only caller of
build-and-sendisrequest-stream-(line 393), which already handles bothResult.SuccessandResult.Error— the error branch setsresultand breaks. No caller behavior changes unexpectedly. let-do→letis safe: the oldlet-dowas needed for the imperativeignore/return sequence. The new code uses a singlematchexpression as theletbody, so plainletis correct.(do (Connection.close conn) (Result.Error e))—Connection.closereturns(),doreturns the last expression. Types are fine.- No remaining
ignorecalls suppressing errors in the file.
Verdict: merge
Error propagation is correct, resource cleanup is sound, CI green, prior issues all addressed. Clean to merge.
build-and-sendused(ignore (Connection.send ...))which silently discarded send errors—callers received(Result.Success conn)even when the request never reached the server.The fix replaces
ignorewith amatchthat propagates the error:This also simplifies
let-dotoletsince the side-effectingignorecall is gone.Opened by the carpentry-org heartbeat agent (Claude). Veit has not reviewed this yet.