Repository navigation
fix(config): fail startup when a static local bind cannot be opened - #2588
Merged
howardjohn merged 5 commits intoAug 4, 2026
Merged
howardjohn merged 5 commits into
howardjohn merged 5 commits into
Conversation
howardjohn
reviewed
Jul 20, 2026
| config.route_groups, | ||
| prev.binds, | ||
| ); | ||
| )?; |
Collaborator
There was a problem hiding this comment.
this will short-circuit the discovery sync which doesn't seem ideal. I am talking about on a new port, after the app has started
Contributor
Author
There was a problem hiding this comment.
Good catch. The ? on sync_local for binds was returning before discovery sync ran.
Updated in e1d2d74:
reload_confignow always runs discovery sync, then propagates any bind error from the binds sync.sync_localonly treats bind failures as fatal for newly added binds (keys not in the previous sync state). Existing binds are not re-opened, which matches the runtime case you described: a new port added after the app has started.
XDS-delivered binds still log-and-continue via insert_bind. Added tests for reload-with-new-bind failure and for config still applying when a bind fails.
howardjohn
approved these changes
Jul 21, 2026
A static local config (`-f config.json`) that could not open a listener socket (e.g. the port was already in use) only logged a warning and kept running, serving nothing on that bind. This is confusing to operators and hides a fatal misconfiguration. `Store::upsert_bind` now returns the bind error instead of swallowing it. `sync_local`, which is only used by the static local config path, collects these errors and returns them so startup propagates the failure and exits non-zero. XDS-delivered binds keep their previous behavior (log and continue) so a bad dynamic config does not crash a running proxy, and config reloads keep the previous good state on error. Signed-off-by: Piyush Jagadish Bag <[email protected]>
Run discovery sync even when a static local bind cannot open, so workload and service state are not skipped on reload. Only treat bind failures for newly added binds as fatal; existing binds are not re-opened. Signed-off-by: Piyush Jagadish Bag <[email protected]>
Apply rustfmt to the sync_local_new_bind_on_reload_failure_is_fatal test bind vector so proxy-lint passes. Signed-off-by: Piyush Jagadish Bag <[email protected]>
Prior run 30025848065: proxy-lint green; integration failed on llm_model_router_handles_multipart_audio_detect_request with [::]:4000 EADDRINUSE (environment), not a fmt/lint regression. Signed-off-by: Piyush Jagadish Bag <[email protected]>
howardjohn
force-pushed
the
fix/static-config-bind-failure-fatal
branch
from
August 4, 2026 20:38
a1a6073 to
d108dd4
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
When running with a static local config (
agentgateway -f config.json), a listener that could not open its OS socket (for example, the port was already in use) only logged a warning and the process kept running, serving nothing on that bind. As reported in #87, this is easy to miss: it looks like the gateway started fine, but the configured listeners are not actually accepting traffic.Approach
Store::upsert_bindnow returns the underlying bind error instead of swallowing it. The bind is still recorded in the store so routing lookups stay consistent.sync_local(used only by the static local config path) collects any bind failures and returns them. The initial config load is awaited at startup, so the error propagates and the process exits non-zero.insert_bind(log and continue), so a bad dynamic config does not crash a running proxy. Config file reloads also keep the last good state on error rather than exiting.This mirrors the common proxy convention where a static listener that cannot bind is fatal, while dynamically delivered listeners are rejected without taking the process down.
Test plan
cargo test -p agentgateway --lib store::binds::(addssync_local_bind_failure_is_fatalandsync_local_bind_success_returns_ok; full module green)cargo clippy -p agentgateway --all-targets(clean)cargo fmt --check -- --config imports_granularity=Module,group_imports=StdExternalCrate,normalize_comments=true(clean)Fixes #87