You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Improve port conflict handling for proxy and API ports - #2030
Dev Proxy now shows a clear, actionable error when the proxy port or the API port is already in use. Previously it printed a Kestrel AddressInUseException stack trace.
Check before startup: in DevProxyCommand.InvokeAsync, after the config is resolved, both ports are checked (PortConflict helper).
If the owner is another Dev Proxy instance (matched via state files):
Port 8000 is already in use by another Dev Proxy instance (PID: 1234).
Stop the existing instance with 'devproxy stop --pid 1234' or use a different port:
devproxy --port 0 (lets the OS assign a free port)
If the owner is another application:
API port 8897 is already in use by another application.
Use a different port:
devproxy --api-port 0 (lets the OS assign a free port)
You can also set 'apiPort' in your devproxyrc.json config file.
Race fallback: if a port is taken between the check and the bind:
KestrelProxyEngine records the failure and stops the host cleanly instead of crashing with a stack trace.
The API-port bind exception is caught and replaced with the same message.
Exit code fix: a taken proxy port previously exited with code 0. It now exits with 1.
Detached mode:
The existing conflict check before startup uses the shared messages and respects --output json.
When the background process exits early, its log (where its console output goes) is shown, so the reason for the failure is visible.
Notes
Instances are detected via state files instead of an HTTP probe. The API requires a bearer token, so an unauthenticated probe can't tell Dev Proxy apart from another server.
The suggested alternative port is 0 (assigned by the OS).
In the rare API-port race, ASP.NET Core's own "Hosting failed to start" error still prints before the friendly message. I didn't change the global logging filters to hide it.
Testing
New PortConflictTests (10 tests). DevProxy.Tests and DevProxy.Proxy.Kestrel.Tests pass.
Manually verified, with both text and JSON output:
Foreground and detached runs, with an unrelated process or another Dev Proxy instance holding the proxy port or the API port.
The race paths, with the check before startup disabled.
Check whether the proxy and API ports are available before starting and
show an actionable error instead of a Kestrel AddressInUseException stack
trace. Identify conflicts with other Dev Proxy instances via their state
files and suggest 'devproxy stop --pid' or '--port 0'/'--api-port 0'.
Also handle bind races without stack traces, exit with code 1 when the
proxy port is taken (previously 0), and surface the daemon's failure
reason when starting in detached mode.
Closesdotnet#1273
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
- Publish instance state only after the proxy listener has started
- Keep detached JSON output valid by wrapping non-JSON log lines
- Match ownership across proxy/API ports and require overlapping bind address
- Use a non-pruning state lookup for port conflict diagnostics
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Unresolved startup and port-conflict handling issues can bypass friendly bind-failure messages, misidentify listener ownership, and block valid launches or restarts.
Match Kestrel's reuse-address option in Unix bind probes
DevProxy/Proxy/PortConflict.cs:44
On Unix, this probe uses default socket options while Kestrel enables SO_REUSEADDR. After traffic and shutdown, connections in TIME_WAIT can make the probe report a conflict even though Kestrel could rebind, preventing valid restarts or hot reloads. Enable ReuseAddress on the probe on non-Windows platforms to match Kestrel.
Make wildcard overlap checks address-family-aware
DevProxy/Proxy/PortConflict.cs:147
An IPv4 wildcard does not overlap an IPv6-only listener: [::1]:8000 and 0.0.0.0:8000 can coexist. This expression nevertheless reports an owner, causing the detached launcher's ownership-only check to reject a valid startup. Make wildcard matching address-family-aware while preserving cross-family overlap for IPv6-any dual-mode binds.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Port-conflict checks can misidentify listeners and block valid launches or restarts, while out-of-range ports bypass normal startup error handling and break JSONL output.
No open issues 🎉
4 previously missed issues
In code that hasn't changed since last review
Check conflicts against config-resolved endpoints
DevProxy/Program.cs:105
This lookup uses CLI-only options and hard-coded defaults, but now also matches the other listener kind. With a non-system-proxy instance on proxy port 8897/API port 8898, a detached run whose config specifies port: 8001 and apiPort: 8899 is newly rejected as an API-port-8897 conflict, even though its actual endpoints are free. Defer this check to the child's existing config-resolved CheckAsync calls so it checks the endpoints that will actually be used.
Skip out-of-range ports in the listener probe
DevProxy/Proxy/PortConflict.cs:31
Ports above 65535 reach the TcpListener constructor, which throws ArgumentOutOfRangeException outside the socket catches and InvokeAsync's startup try. Consequently, devproxy --output json --port 65536 now reaches Program.cs's plain-text unhandled-exception handler and breaks JSONL output. Skip out-of-range ports here, just as negative ports are skipped, so the normal startup error handling can report them.
Enable SO_REUSEADDR for Unix port probes
DevProxy/Proxy/PortConflict.cs:44
On Unix, this probe does not enable SO_REUSEADDR as Kestrel does, so a port with a connection in TIME_WAIT can fail the probe even though Kestrel could bind it. This blocks otherwise valid restarts and hot reloads and incorrectly reports another application. Match Kestrel's Unix socket reuse setting before starting the probe.
Make IPv4 wildcard matching address-family-aware
DevProxy/Proxy/PortConflict.cs:147
An IPv4 wildcard does not overlap IPv6 loopback, so this predicate can identify a Dev Proxy instance on ::1:8000 as the owner of another application's IPv4 listener and recommend a stop command that will not free the port. The detached precheck can also reject this combination when the IPv4 port is free. Make IPv4 wildcard matching address-family-aware while preserving dual-stack IPv6 wildcard overlap.
- Drop the detached launcher's CLI-only conflict pre-check; the daemon's
config-aware check reports conflicts instead
- Skip the listener probe for ports above 65535 and validate --port and
--api-port to the 0-65535 range
- Treat 0.0.0.0 as overlapping IPv4 addresses only; :: stays dual-stack
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Addressing the 4 "previously missed issues" from Copilot's review of 7d5fcb0 (fixed in 446b9fc):
Check conflicts against config-resolved endpoints (Program.cs): Fixed. I removed the detached launcher's pre-check, which only looked at CLI ports. The daemon's config-aware CheckAsync reports conflicts now; the launcher prints that output, and it stays valid JSONL with --output json. Verified: a detached launch that conflicts with a running instance reports that instance's PID and the stop hint.
Skip out-of-range ports in the listener probe: Fixed. The probe skips ports above 65535, the same way it already skipped ports ≤ 0, and --port/--api-port now only accept 0–65535 (exit code 2). Tests added. In --output json mode the validation error is still plain text, but every option validator (for example --timeout) already behaves that way, so that's outside this PR's scope.
Make IPv4 wildcard matching address-family-aware: Fixed. 0.0.0.0 now overlaps IPv4 addresses only, while :: is still treated as dual-stack. Tests added for 0.0.0.0 vs [::1] and the reverse.
Enable SO_REUSEADDR for Unix port probes: Not changing this. Hot reload waits for the host to shut down before the next startup runs the probe. We haven't reproduced a false conflict from TIME_WAIT. If someone reports a false positive, we'll revisit.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Human assessment is needed because platform-specific port probing and startup/shutdown sequencing can falsely report conflicts, bypass intended validation, or stall shutdown during certificate-trust prompts.
Re: Copilot's review of 446b9fc ("Needs a closer look"). It didn't flag any specific lines; here's my assessment of the three concerns it mentions:
Platform-specific port probing could report false conflicts: this is the SO_REUSEADDR item covered in my previous comment. Not changing it unless someone reproduces a false positive.
Shutdown could stall during the certificate-trust prompt: not a regression. EnsureTrusted runs synchronously in KestrelProxyEngine.ExecuteAsync before its first await, and hosted services start one at a time by default. So the prompt blocks _app.StartAsync exactly as it does on main, and it has already been answered by the time InvokeAsync waits on Started.
Validation can be bypassed:--port/--api-port are now limited to 0–65535. Ports set in the config file aren't covered by that CLI validator. Out-of-range config values skip the conflict probe, and Kestrel reports them the same way it does on main, so this PR doesn't change that path.
This branch has not been deployed
No deployments
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
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.
Closes #1273
Summary
Dev Proxy now shows a clear, actionable error when the proxy port or the API port is already in use. Previously it printed a Kestrel
AddressInUseExceptionstack trace.DevProxyCommand.InvokeAsync, after the config is resolved, both ports are checked (PortConflicthelper).KestrelProxyEnginerecords the failure and stops the host cleanly instead of crashing with a stack trace.--output json.Notes
0(assigned by the OS).Testing
PortConflictTests(10 tests).DevProxy.TestsandDevProxy.Proxy.Kestrel.Testspass.