Skip to content

stale connection retries - #3967

Merged
akshaydeo merged 1 commit into
devfrom
06-02-stale_connection_retries
Jun 2, 2026
Merged

stale connection retries#3967
akshaydeo merged 1 commit into
devfrom
06-02-stale_connection_retries

Conversation

@akshaydeo

@akshaydeo akshaydeo commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Summary

StaleConnectionRetryIfErr was not retrying on several real-world connection-closure errors because it relied on direct equality checks (err == io.EOF) and a fixed set of string patterns. Wrapped errors (e.g. fmt.Errorf("read response: %w", io.EOF)) were silently falling through without a retry, and error strings like "use of closed network connection" and "server closed connection" were not covered.

Changes

  • Replaced err == io.EOF with errors.Is(err, io.EOF) so wrapped EOF errors are correctly detected.
  • Added errors.Is(err, io.ErrUnexpectedEOF) to handle unexpected EOF variants.
  • Added string match patterns for "use of closed network connection" and "server closed connection" to cover additional OS- and fasthttp-level connection closure signals.
  • Added an early-exit guard for fasthttp.ErrConnectionClosed to avoid retrying when fasthttp has already handled the error post-loop.
  • Switched err.Error() to strings.ToLower(err.Error()) for case-insensitive string matching consistency.
  • Added corresponding test cases for wrapped io.EOF, io.ErrUnexpectedEOF, wrapped io.ErrUnexpectedEOF, "use of closed network connection", and "server closed connection".

Type of change

  • Bug fix
  • Feature
  • Refactor
  • Documentation
  • Chore/CI

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (React)
  • Docs

How to test

go test ./core/network/... -v -run TestStaleConnectionRetryIfErr

All existing and new test cases should pass, including the wrapped EOF and new connection-closure string variants.

Breaking changes

  • Yes
  • No

Related issues

Security considerations

None. This change only affects retry logic for stale HTTP connections and does not touch authentication, secrets, or PII handling.

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate
  • I updated documentation where needed
  • I verified builds succeed (Go and UI)
  • I verified the CI pipeline passes locally if applicable

Summary by CodeRabbit

  • Bug Fixes

    • Improved HTTP client resilience by expanding retry behavior to handle a broader set of EOF and connection-closed scenarios.
  • Tests

    • Expanded test coverage to validate additional EOF, wrapped-EOF, and server-closure cases.
  • Chores

    • Minor formatting adjustment to an example configuration file.

@coderabbitai

coderabbitai Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: bc45c088-65fc-4f41-a3ee-e39887cf0261

📥 Commits

Reviewing files that changed from the base of the PR and between 7d7f118 and 5236f8f.

📒 Files selected for processing (3)
  • core/network/http.go
  • core/network/http_test.go
  • examples/configs/withotel/config.json

📝 Walkthrough

Walkthrough

Broadens fasthttp stale-connection retry detection to include wrapped and unexpected EOFs and additional closed/broken-connection message variants, expands tests to cover these cases, and adjusts EOF formatting in an example config file.

Changes

HTTP Stale Connection Retry Logic Enhancement

Layer / File(s) Summary
Enhanced retry error handling
core/network/http.go
Added errors import and reworked StaleConnectionRetryIfErr to explicitly handle fasthttp.ErrConnectionClosed, use errors.Is for io.EOF and io.ErrUnexpectedEOF, and perform a single lowercased substring match for additional closed/broken-connection messages.
Test coverage for expanded retry scenarios
core/network/http_test.go
Expanded TestStaleConnectionRetryIfErr table to include direct and wrapped io.EOF, io.ErrUnexpectedEOF, and TCP/server-closure variants; asserts wantReset/wantRetry accordingly and includes a minor spacing alignment change in an unrelated test line.

Configuration File Formatting

Layer / File(s) Summary
Config file formatting
examples/configs/withotel/config.json
Adjusted final closing-brace / end-of-file formatting.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • danpiths

Poem

🐰 A socket hiccup in the night,
EOF ghosts gave the client a fright,
Wrapped errors found their proper place,
Retry rules now spot the trace,
The rabbit hops — connections right!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'stale connection retries' directly and concisely describes the main change: improving retry detection for stale HTTP connection errors.
Description check ✅ Passed The description comprehensively covers the summary, detailed changes, type of change, affected areas, testing instructions, and other template sections with substantive content.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 06-02-stale_connection_retries

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


Comment @coderabbitai help to get the list of available commands and usage tips.

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@akshaydeo
akshaydeo marked this pull request as ready for review June 1, 2026 20:06

akshaydeo commented Jun 1, 2026

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@greptile-apps

greptile-apps Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 4/5

Mostly safe retry improvements, but the io.ErrUnexpectedEOF addition can re-submit POST requests when the server already processed them.

The io.ErrUnexpectedEOF branch is the one genuinely risky addition: when fasthttp reads a response body with a Content-Length and the connection drops mid-body, it surfaces io.ErrUnexpectedEOF. The server has already processed the POST at that point, so retrying sends a second LLM inference request. The remaining changes (errors.Is for EOF, new string patterns, strings.ToLower) are correct.

core/network/http.go — specifically the errors.Is(err, io.ErrUnexpectedEOF) condition in StaleConnectionRetryIfErr.

Important Files Changed

Filename Overview
core/network/http.go Expands StaleConnectionRetryIfErr with errors.Is for wrapped errors and new string patterns; the io.ErrUnexpectedEOF addition can trigger unsafe retries on mid-response failures, not just stale connections.
core/network/http_test.go Adds table-driven test cases for wrapped EOF, unexpected EOF, use of closed network connection, server closed connection, and fasthttp.ErrConnectionClosed; coverage is good for the happy retry paths but lacks a negative-case test for io.ErrUnexpectedEOF in a mid-response context.
examples/configs/withotel/config.json Cosmetic: removed trailing newline from the final closing brace.

Reviews (4): Last reviewed commit: "stale connection retries" | Re-trigger Greptile

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@core/network/http_test.go`:
- Around line 49-90: The new early-return branch for
fasthttp.ErrConnectionClosed in the retry logic is untested; add a table-driven
test case in the existing test table (core/network/http_test.go) that uses err:
fasthttp.ErrConnectionClosed and asserts the expected behavior (no retry and no
reset per the fasthttp.ErrConnectionClosed branch), and either add or replace
the existing "server closed connection" case so it uses the actual
fasthttp.ErrConnectionClosed sentinel (rather than a fmt.Errorf string) to
exercise that code path and close the coverage gap.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: e1f21ae0-1fc1-4054-ac7a-22ea6f5af72c

📥 Commits

Reviewing files that changed from the base of the PR and between a70594c and 66d1cee.

📒 Files selected for processing (3)
  • core/network/http.go
  • core/network/http_test.go
  • examples/configs/withotel/config.json

Comment thread core/network/http_test.go
@akshaydeo
akshaydeo force-pushed the 06-02-stale_connection_retries branch from 66d1cee to 9c33870 Compare June 1, 2026 21:17

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@core/network/http.go`:
- Around line 262-276: The early return that checks errors.Is(err,
fasthttp.ErrConnectionClosed) prevents RetryIfErr from treating a stale
keep-alive close as retryable; update the logic in the RetryIfErr callback so
that fasthttp.ErrConnectionClosed is handled like the other stale-connection
cases (either remove the early return or include fasthttp.ErrConnectionClosed in
the retryable conditions alongside io.EOF/io.ErrUnexpectedEOF and the string
checks) so stale-connection errors from fasthttp v1.68.0 will trigger the retry
path; ensure you reference fasthttp.ErrConnectionClosed and the RetryIfErr
callback when making the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4faa3ceb-b808-469f-8bd8-1e729c7fc8f2

📥 Commits

Reviewing files that changed from the base of the PR and between 66d1cee and 9c33870.

📒 Files selected for processing (3)
  • core/network/http.go
  • core/network/http_test.go
  • examples/configs/withotel/config.json

Comment thread core/network/http.go Outdated
@akshaydeo
akshaydeo force-pushed the 06-02-stale_connection_retries branch from 9c33870 to 7d7f118 Compare June 1, 2026 21:37
Comment thread core/network/http.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@core/network/http_test.go`:
- Around line 91-100: The test in http_test.go incorrectly expects
fasthttp.ErrConnectionClosed to not retry; update the test case for the "does
not retry on fasthttp.ErrConnectionClosed sentinel" entry so its expectations
match the current http.go behavior: set wantRetry to true and wantReset to true
(since http.go returns (true, true) for errors.Is(err,
fasthttp.ErrConnectionClosed)). Locate the test case by the sentinel value
fasthttp.ErrConnectionClosed and adjust the attempts/wantReset/wantRetry fields
accordingly to reflect the implementation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 66824468-71c5-4b70-b75f-7f7bf8251d6f

📥 Commits

Reviewing files that changed from the base of the PR and between 9c33870 and 7d7f118.

📒 Files selected for processing (3)
  • core/network/http.go
  • core/network/http_test.go
  • examples/configs/withotel/config.json

Comment thread core/network/http_test.go
@akshaydeo
akshaydeo force-pushed the 06-02-stale_connection_retries branch from 7d7f118 to 5236f8f Compare June 2, 2026 06:05

akshaydeo commented Jun 2, 2026

Copy link
Copy Markdown
Contributor Author

Merge activity

  • Jun 2, 6:44 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Jun 2, 6:44 AM UTC: @akshaydeo merged this pull request with Graphite.

@akshaydeo
akshaydeo merged commit d9c28c2 into dev Jun 2, 2026
13 of 14 checks passed
@akshaydeo
akshaydeo deleted the 06-02-stale_connection_retries branch June 2, 2026 06:44
akshaydeo added a commit that referenced this pull request Jun 2, 2026
## Summary

`StaleConnectionRetryIfErr` was not retrying on several real-world connection-closure errors because it relied on direct equality checks (`err == io.EOF`) and a fixed set of string patterns. Wrapped errors (e.g. `fmt.Errorf("read response: %w", io.EOF)`) were silently falling through without a retry, and error strings like `"use of closed network connection"` and `"server closed connection"` were not covered.

## Changes

- Replaced `err == io.EOF` with `errors.Is(err, io.EOF)` so wrapped EOF errors are correctly detected.
- Added `errors.Is(err, io.ErrUnexpectedEOF)` to handle unexpected EOF variants.
- Added string match patterns for `"use of closed network connection"` and `"server closed connection"` to cover additional OS- and fasthttp-level connection closure signals.
- Added an early-exit guard for `fasthttp.ErrConnectionClosed` to avoid retrying when fasthttp has already handled the error post-loop.
- Switched `err.Error()` to `strings.ToLower(err.Error())` for case-insensitive string matching consistency.
- Added corresponding test cases for wrapped `io.EOF`, `io.ErrUnexpectedEOF`, wrapped `io.ErrUnexpectedEOF`, `"use of closed network connection"`, and `"server closed connection"`.

## Type of change

- [x] Bug fix
- [ ] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [ ] Core (Go)
- [x] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [ ] UI (React)
- [ ] Docs

## How to test

```sh
go test ./core/network/... -v -run TestStaleConnectionRetryIfErr
```

All existing and new test cases should pass, including the wrapped EOF and new connection-closure string variants.

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

## Security considerations

None. This change only affects retry logic for stale HTTP connections and does not touch authentication, secrets, or PII handling.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **Bug Fixes**
  * Improved HTTP client resilience by expanding retry behavior to handle a broader set of EOF and connection-closed scenarios.

* **Tests**
  * Expanded test coverage to validate additional EOF, wrapped-EOF, and server-closure cases.

* **Chores**
  * Minor formatting adjustment to an example configuration file.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
akshaydeo added a commit that referenced this pull request Jun 4, 2026
## Summary

`StaleConnectionRetryIfErr` was not retrying on several real-world connection-closure errors because it relied on direct equality checks (`err == io.EOF`) and a fixed set of string patterns. Wrapped errors (e.g. `fmt.Errorf("read response: %w", io.EOF)`) were silently falling through without a retry, and error strings like `"use of closed network connection"` and `"server closed connection"` were not covered.

## Changes

- Replaced `err == io.EOF` with `errors.Is(err, io.EOF)` so wrapped EOF errors are correctly detected.
- Added `errors.Is(err, io.ErrUnexpectedEOF)` to handle unexpected EOF variants.
- Added string match patterns for `"use of closed network connection"` and `"server closed connection"` to cover additional OS- and fasthttp-level connection closure signals.
- Added an early-exit guard for `fasthttp.ErrConnectionClosed` to avoid retrying when fasthttp has already handled the error post-loop.
- Switched `err.Error()` to `strings.ToLower(err.Error())` for case-insensitive string matching consistency.
- Added corresponding test cases for wrapped `io.EOF`, `io.ErrUnexpectedEOF`, wrapped `io.ErrUnexpectedEOF`, `"use of closed network connection"`, and `"server closed connection"`.

## Type of change

- [x] Bug fix
- [ ] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [ ] Core (Go)
- [x] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [ ] UI (React)
- [ ] Docs

## How to test

```sh
go test ./core/network/... -v -run TestStaleConnectionRetryIfErr
```

All existing and new test cases should pass, including the wrapped EOF and new connection-closure string variants.

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

## Security considerations

None. This change only affects retry logic for stale HTTP connections and does not touch authentication, secrets, or PII handling.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **Bug Fixes**
  * Improved HTTP client resilience by expanding retry behavior to handle a broader set of EOF and connection-closed scenarios.

* **Tests**
  * Expanded test coverage to validate additional EOF, wrapped-EOF, and server-closure cases.

* **Chores**
  * Minor formatting adjustment to an example configuration file.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
@akshaydeo akshaydeo mentioned this pull request Jun 5, 2026
18 tasks
akshaydeo added a commit that referenced this pull request Jun 6, 2026
## Summary

This PR bumps the Go toolchain version from `1.26.3` to `1.26.4` across all modules and CI workflows, and cuts a new release (`core` v1.5.17, `framework` v1.3.17, `transports` v1.5.9, `plugins/compat` v0.1.16, `plugins/governance` v1.5.17, and associated plugin versions) incorporating a large batch of features and fixes accumulated since the previous release.

## Changes

- **Go 1.26.4** — Updated `go-version` in all GitHub Actions workflows (`e2e-tests`, `helm-release`, `pr-tests`, `release-cli`, `release-pipeline`, `snyk`) and all `go.mod` files (core, framework, transports, cli, all plugins, examples, and test modules).
- **Core (v1.5.17)** — OpenAI compaction support, multi-customer logs and usage tracking, multiple team/business unit support, `request_headers` wildcard pattern capture for OTel and Maxim plugins, xAI `x_search` tool, fetch URL validation with SSRF hardening, `file://` pricing URL scheme, virtual key provider fan-out filtering, and a broad set of fixes including Anthropic prompt cache key, empty thinking block stripping, OpenAI stream usage event cleanup, Gemini numeric schema constraints, stale connection retries, Azure Claude diagnostic strip, and passthrough budget handling.
- **Framework (v1.3.17)** — Scope-aware budgets and limits wired from model configs, provider-level governance, multiple customer budget support with `calendar_aligned` windows, paginated virtual key fetch, `config.json` source-of-truth flow, FTS index cap reduction, sync worker drift fix, cascade deletes for model configs, and high-scale virtual key flow improvements.
- **Transports (v1.5.9)** — Full changelog covering all of the above plus UI improvements (log navigation, customer detail sheet, `BudgetDisplay` component, inline loading shell, materialized view alias), SCIM provisioning fields, Helm/config schema additions (`roles`, `per_user_oauth`), client IP resolution from forwarded headers, and dependency upgrades (`recharts` to 3.8.1, `golang.org/x` CVE remediation).
- **Plugins** — `governance` v1.5.17 adds team budget/rate-limit exporters, ghost node reconciliation fix, and VK double usage counting fix; `logging` v1.5.17 adds wildcard header capture and file attachment rendering; `otel` v1.2.17 adds `disable_content_logging` and multiple collectors support; `maxim` v1.6.17 adds `request_headers` wildcard capture; `compat` v0.1.16 fixes `max_tokens` preservation during param filtering.

## Type of change

- [ ] Bug fix
- [x] Feature
- [ ] Refactor
- [ ] Documentation
- [x] Chore/CI

## Affected areas

- [x] Core (Go)
- [x] Transports (HTTP)
- [x] Providers/Integrations
- [x] Plugins
- [x] UI (React)
- [ ] Docs

## How to test

```sh
# Verify Go version
go version  # should report go1.26.4

# Run core tests
cd core && go test ./...

# Run framework tests
cd framework && go test ./...

# Run transports tests
cd transports && go test ./...

# Run plugin tests
cd plugins/governance && go test ./...
cd plugins/logging && go test ./...
cd plugins/otel && go test ./...

# UI
cd ui
pnpm i
pnpm build
pnpm test
```

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

#4053, #4066, #4041, #4012, #3976, #3947, #3991, #4045, #3957, #3938, #3937, #3939, #3981, #3998, #3997, #4092, #4091, #4079, #4080, #4086, #3929, #3994, #4028, #3970, #3919, #3861, #3664, #3999, #4088, #4070, #4051, #4043, #4057, #4023, #3941, #3955, #4024, #3956, #3967, #3925, #3992, #3900

## Security considerations

- Fetch URL validation hardened against SSRF by tightening IP checks for private networks and link-local addresses (#4092, #3947, #3991).
- Transitive `golang.org/x` dependencies (crypto, net, sys, text) bumped to address Docker Scout CVEs (#3900).

## Checklist

- [x] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [x] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [x] I verified the CI pipeline passes locally if applicable

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * OpenAI compaction, multi-customer/team logstore support, request-header wildcard capture, enhanced governance (provider-level & scope-aware limits), disable-content-logging option, support for multiple OpenTelemetry collectors, SSRF hardening and URL validation.

* **Chores**
  * Bumped Go toolchain across modules and updated component/plugin version releases.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
@akshaydeo akshaydeo mentioned this pull request Jun 7, 2026
akshaydeo added a commit that referenced this pull request Jun 7, 2026
## Summary

`StaleConnectionRetryIfErr` was not retrying on several real-world connection-closure errors because it relied on direct equality checks (`err == io.EOF`) and a fixed set of string patterns. Wrapped errors (e.g. `fmt.Errorf("read response: %w", io.EOF)`) were silently falling through without a retry, and error strings like `"use of closed network connection"` and `"server closed connection"` were not covered.

## Changes

- Replaced `err == io.EOF` with `errors.Is(err, io.EOF)` so wrapped EOF errors are correctly detected.
- Added `errors.Is(err, io.ErrUnexpectedEOF)` to handle unexpected EOF variants.
- Added string match patterns for `"use of closed network connection"` and `"server closed connection"` to cover additional OS- and fasthttp-level connection closure signals.
- Added an early-exit guard for `fasthttp.ErrConnectionClosed` to avoid retrying when fasthttp has already handled the error post-loop.
- Switched `err.Error()` to `strings.ToLower(err.Error())` for case-insensitive string matching consistency.
- Added corresponding test cases for wrapped `io.EOF`, `io.ErrUnexpectedEOF`, wrapped `io.ErrUnexpectedEOF`, `"use of closed network connection"`, and `"server closed connection"`.

## Type of change

- [x] Bug fix
- [ ] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [ ] Core (Go)
- [x] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [ ] UI (React)
- [ ] Docs

## How to test

```sh
go test ./core/network/... -v -run TestStaleConnectionRetryIfErr
```

All existing and new test cases should pass, including the wrapped EOF and new connection-closure string variants.

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

## Security considerations

None. This change only affects retry logic for stale HTTP connections and does not touch authentication, secrets, or PII handling.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **Bug Fixes**
  * Improved HTTP client resilience by expanding retry behavior to handle a broader set of EOF and connection-closed scenarios.

* **Tests**
  * Expanded test coverage to validate additional EOF, wrapped-EOF, and server-closure cases.

* **Chores**
  * Minor formatting adjustment to an example configuration file.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
akshaydeo added a commit that referenced this pull request Jun 7, 2026
## ✨ Features

- **OpenAI Compaction** — Added OpenAI conversation compaction support
across core, framework, logging, and the API surface (#4053)
- **Multi-Customer & Org Hierarchy** — Logs and usage tracking now
support multiple customers, teams, and business units, including
business unit CRUD, team assignment, and governance endpoints in the
OpenAPI spec (#4066, #4041, #4082)
- **Provider-Level Governance** — Budgets & limits are now scope-aware
and can be applied at the virtual-key top level and per provider, wired
from the model configs table, with UI filters for scope and providers
(#3938, #3937, #3939, #3981, #3962)
- **Customer Budgets** — Customers support multiple budgets and
`calendar_aligned` budget windows (#3998, #3997)
- **Virtual Key Attribution & Controls** — Added a `created_by` user
attribution column and a `blacklisted_models` column for virtual key
provider configs (#3672, #3653)
- **Request Header Capture** — OTel and Maxim observability plugins
capture `request_headers` by pattern, with wildcard support (e.g.
`x-custom-*`); logging gained the same wildcard header capture (#4012,
#3958)
- **OTel Content Controls & Collectors** — New `disable_content_logging`
option drops message/tool content from exported spans, plus support for
multiple OTel collectors (#4064, #3894)
- **xAI x_search** — Added xAI `x_search` tool support (#3976)
- **URL Validation** — Added fetch URL validation with private-network
configuration and link-local blocking (#3947, #3991)
- **File Scheme Pricing URLs** — Pricing source URLs now accept the
`file://` scheme for air-gapped and self-hosted deployments (#4045)
- **Paginated Virtual Keys** — Virtual key fetching is paginated to
handle deployments with very large numbers of keys (#3957)
- **Client IP Resolution** — Resolve client IP from
`X-Forwarded-For`/`X-Real-IP` headers
- **SCIM Provisioning** — Added `attributeType`/`attributeValue` SCIM
provisioning fields
- **Helm/Config Schema** — Added `roles` RBAC governance config and
`per_user_oauth` MCP auth to the Helm chart and config schema (#4004,
#4009)
- **Log Navigation UI** — Added a "View logs" menu item to customer,
team, and virtual key tables, clickable links in log detail views, a
customer detail sheet, and a reusable `BudgetDisplay` component (#4073,
#4054, #4026, #4055)
- **Faster First Paint** — Added an inline loading shell to `#root`
before React mounts (#4063)
- **Materialized View Alias** — Added an `alias` column to the
materialized view with filter support (#4078)

## 🐞 Fixed

- **Fetch URL IP Checks** — Hardened fetch URL IP checks against SSRF
(#4092)
- **Mantle Model Matching** — Broadened Mantle model matching to all
`gpt` variants (#4091)
- **Empty Thinking Blocks** — Strip thinking blocks when the signature
is empty (#4079)
- **OpenAI Stream Usage** — Removed usage from the `responses.created`
event in the OpenAI stream (#4080)
- **Prompt Cache Key** — Set the prompt cache key from the Anthropic
integration (#4086)
- **Upstream Failure Status** — Map upstream connection failures to 502
instead of 400 (#3929) (thanks
[@chris-colinsky](https://github.com/chris-colinsky)!)
- **Gemini Schema Constraints** — Accept numeric schema integer
constraints for Gemini (#3994) (thanks
[@yanhao98](https://github.com/yanhao98)!)
- **Files Provider Param** — Accept the `?provider=` query param on `GET
/v1/files` (#3971) (thanks [@alexef](https://github.com/alexef)!)
- **Optional Batch Model** — Made the `model` field optional on `POST
/v1/batches` (#3973) (thanks [@alexef](https://github.com/alexef)!)
- **Helm Azure Config** — Added missing `azure_key_config` fields to the
Helm schema (#3996) (thanks
[@axelray-dev](https://github.com/axelray-dev)!)
- **Text Completion Chunk Model** — Added the missing `Model` field to
`TextCompletionChunkResponse` (#3970) (thanks
[@kuishou68](https://github.com/kuishou68)!)
- **MCP Inline stdio Env** — MCP stdio server configs accept inline
environment variable assignments (#3861) (thanks
[@Shushmitaaaa](https://github.com/Shushmitaaaa)!)
- **Orphaned Tool Results** — Orphaned tool results in the OpenAI to
Anthropic conversion flow are no longer rejected by the Anthropic API
(#3919)
- **Node Usage Reconciliation** — Added a monotonic `inc_number` log
cursor so node usage reconciliation does not skip late async log writes
(#3664)
- **Bedrock Output Assessments** — Corrected the type of
`outputAssessments` in Bedrock responses (#4028)
- **Model Pool Pricing Reloads** — Preserve non-pricing model pool
entries across pricing reloads (#3999)
- **Ghost Node Reconciliation** — Replicate the VK hierarchy flow for
ghost node reconciliation (#4088)
- **VK Double Usage Counting** — Fixed double usage counting when
creating a virtual key (#4070)
- **Model Config Lifecycle** — Cascade deletes for model configs and
removal of stale in-memory model configs (#4051, #4043)
- **FTS Index Cap** — Reduced the FTS index `left()` cap from 800k to
250k chars to stay within the tsvector limit (#4057)
- **Sync Worker Drift** — Reduced the sync worker ticker period to 5m to
prevent threshold drift (#4023)
- **Passthrough** — Fixed passthrough budgets, gated passthrough models
per VK, model extraction for Azure passthrough, and restricted
fallbacks/provider selection to the VK boundary (#3941, #3988, #3983,
#3924)
- **Provider Response Headers** — Strip provider response headers and
add a content-type filter (#3955, #4024)
- **Stream Handling** — Drain non-SSE stream readers and retry stale
connections (#3956, #3967)
- **Azure Claude** — Strip Azure diagnostic property for Claude models
(#3925)
- **Compat max_tokens** — Preserve chat `max_tokens` during param
filtering (#3992)
- **Raw Request Flag** — Removed the raw request flag from providers
that don't support it (#4058)
- **UI Fixes** — Standardized page container layout, virtual key model
configs UI, and dashboard chart tooltips (#4046, #4052, #4044)

## 🔧 Maintenance

- **Dependency Upgrades** — Bumped transitive `golang.org/x`
dependencies (crypto, net, sys, text) for Docker Scout CVE remediation
and `recharts` to 3.8.1; cascaded version bumps across all modules
(#3900, #4003)
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.

2 participants