{"record":{"id":"cdad3583c1d674b6","repo":"siyuan-note/siyuan","slug":"nil-response","errorCode":null,"errorMessage":"nil response","messagePattern":"nil response","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/httprequest.go","lineNumber":338,"sourceCode":"\n\tvar reqBody io.Reader\n\tif body != \"\" && method != \"GET\" && method != \"HEAD\" {\n\t\treqBody = strings.NewReader(body)\n\t}\n\treq, err := http.NewRequest(method, rawURL, reqBody)\n\tif err != nil {\n\t\treturn 0, \"\", \"\", errors.New(\"invalid request: \" + err.Error())\n\t}\n\tfor k, v := range headers {\n\t\treq.Header.Set(k, v)\n\t}\n\n\tresp, err := ssrfSafeClient.Do(req)\n\tif err != nil {\n\t\treturn 0, \"\", \"\", errors.New(\"request failed: \" + err.Error())\n\t}\n\tif resp == nil {\n\t\treturn 0, \"\", \"\", errors.New(\"nil response\")\n\t}\n\tdefer resp.Body.Close()\n\n\tstatusCode = resp.StatusCode\n\tcontentType = resp.Header.Get(\"Content-Type\")\n\n\tmaxReadBytes := int64(maxHTTPRequestBytes)\n\tif !isTextContentType(contentType) {\n\t\tmaxReadBytes = maxHTTPRequestFileBytes\n\t}\n\t// ContentLength 为 -1（chunked）时跳过大小预检，交由 LimitReader 兜底截断。\n\tif resp.ContentLength > maxReadBytes {\n\t\treturn statusCode, contentType, \"\", errors.New(\"response too large\")\n\t}\n\n\trespBody, rerr := io.ReadAll(io.LimitReader(resp.Body, maxReadBytes))\n\tif rerr != nil {\n\t\treturn statusCode, contentType, \"\", errors.New(\"read body failed: \" + rerr.Error())","sourceCodeStart":320,"sourceCodeEnd":356,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/util/httprequest.go#L320-L356","documentation":"HTTPRequest in kernel/util/httprequest.go performs an SSRF-safe outbound HTTP call for the agent's http_request tool. After ssrfSafeClient.Do returns without an error, the code defensively checks that a non-nil *http.Response was returned. Go's net/http normally guarantees a non-nil response whenever err is nil, so this error is thrown when an internal invariant of the custom SSRF-safe transport is violated and Do returns (nil, nil).","triggerScenarios":"Calling HTTPRequest(method, rawURL, headers, body) where the ssrfSafeClient's RoundTrip implementation returns (nil, nil) — a bug or edge case in the custom ssrfSafeTransport/proxy tunnel path rather than anything the caller can control via arguments.","commonSituations":"Encountered when diagnosing the proxy-tunnel transport (HTTP CONNECT or SOCKS5 path) in environments using HTTP_PROXY/HTTPS_PROXY/ALL_PROXY, or after custom modifications to ssrfSafeClient; practically never seen in normal direct-connection usage.","solutions":["Check environment proxy variables (HTTP_PROXY/HTTPS_PROXY/ALL_PROXY, NO_PROXY) and retry with the proxy disabled to confirm the proxy tunnel path is the trigger","Inspect the ssrfSafeTransport.RoundTrip implementation in kernel/util/httprequest.go for a code path returning nil response with nil error and fix it to always return a non-nil error alongside a nil response","Update to the latest kernel build in case the transport invariant bug has been patched","Retry the request once — if it recurs deterministically, report it as a kernel bug with the target URL and proxy configuration"],"exampleFix":"// before (in a custom RoundTrip)\nif somethingOdd {\n    return nil, nil // violates net/http contract\n}\n// after\nif somethingOdd {\n    return nil, errors.New(\"transport produced no response\")\n}","handlingStrategy":"try-catch","validationCode":"// Go has no pre-call validation; the invariant is internal to ssrfSafeClient.\n// Sanity-check inputs before the call:\nif !strings.HasPrefix(rawURL, \"http://\") && !strings.HasPrefix(rawURL, \"https://\") {\n    return errors.New(\"URL must start with http:// or https://\")\n}","typeGuard":"if resp == nil {\n    // treat as an error path before dereferencing resp\n    return errors.New(\"nil response\")\n}","tryCatchPattern":"status, ct, text, err := util.HTTPRequest(method, url, headers, body)\nif err != nil {\n    if strings.Contains(err.Error(), \"nil response\") {\n        // internal transport invariant violation: log and report, do not retry blindly\n        return fmt.Errorf(\"http_request tool returned nil response: %w\", err)\n    }\n    return err\n}","preventionTips":["Keep the SSRF-safe transport on an unmodified, up-to-date kernel build","When using proxies, verify the tunnel path behaves correctly with a simple GET before relying on it in automation","Never dereference the response without checking err and resp for nil"],"tags":["http","network","defensive-check","go"],"backgroundTag":"null-argument","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}