From 70037cf71f1ae14175781e162c9c76d1ac730ece Mon Sep 17 00:00:00 2001 From: Moses Narrow <36607567+0pcom@users.noreply.github.com> Date: Tue, 14 Jul 2026 19:34:14 -0500 Subject: [PATCH] net/http: fix nil didTimeout deref when a client dial fails Client.do calls didTimeout() on the error path (line 461), and the contract is that send() returns a non-nil didTimeout whenever err != nil. TinyGo dropped setRequestCancel but left the roundTrip error path returning the nil named return value, so any http.Client{Timeout: ...} request whose dial failed (e.g. connection refused) panicked with a nil func-value dereference instead of returning the error. Return alwaysFalse on those error paths, matching the other error returns in send(). Verified: http.Client{Timeout}.Get to a refused port now returns "connection refused" instead of panicking. --- http/client.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/http/client.go b/http/client.go index ff84425..6f6589e 100644 --- a/http/client.go +++ b/http/client.go @@ -213,10 +213,14 @@ func send(req *Request, deadline time.Time) (resp *Response, didTimeout func() b // TINYGO: Remove TLS error check - return nil, didTimeout, err + // didTimeout must be non-nil whenever err != nil: c.do calls + // didTimeout() on the error path. The named return is nil here (TinyGo + // dropped setRequestCancel), so return alwaysFalse instead to avoid a + // nil func-value dereference on a failed dial. + return nil, alwaysFalse, err } if resp == nil { - return nil, didTimeout, fmt.Errorf("http: sendit returned a nil *Response with a nil error") + return nil, alwaysFalse, fmt.Errorf("http: sendit returned a nil *Response with a nil error") } // TINYGO: Skip check for resp.Body == nil since we'll set it in roundTrip