XTLS/Xray-core · warning · errors.Error
underlying connection error
Error message
underlying connection error
What it means
Created in app/observatory/explainErrors.go:11 by errorCollector.SubmitError: it is the wrapper label prepended to the first underlying connection error recorded during an observatory probe. Xray's session system tracks connection errors through the dispatch path, and this collector chains them so the final probe report can explain why a connection died.
Source
Thrown at app/observatory/explainErrors.go:11
package observatory
import "github.com/xtls/xray-core/common/errors"
type errorCollector struct {
errors *errors.Error
}
func (e *errorCollector) SubmitError(err error) {
if e.errors == nil {
e.errors = errors.New("underlying connection error").Base(err)
return
}
e.errors = e.errors.Base(errors.New("underlying connection error").Base(err))
}
func newErrorCollector() *errorCollector {
return &errorCollector{}
}
func (e *errorCollector) UnderlyingError() error {
if e.errors == nil {
return errors.New("failed to produce report")
}
return e.errors
}
View on GitHub (pinned to 7d214f8b09)
Solutions
- Read the chained error (Base) — run err with %v in a multi-error-aware logger or inspect errors.Error path — to find the true cause.
- Fix the underlying outbound: check server reachability, credentials, and TLS settings of the proxy being probed.
- If the probe target itself is unreachable from the server, set probeUrl in the observatory config to a host you can reach.
Defensive patterns
Strategy: fallback
Try / catch
// consumers of observatory results: this is a warning-chain wrapper, not a failure to handle
if result.Alive { keepOutbound() } else { logChainedErrors(result.LastErrorReason) } Prevention
- Log the full Base chain so the wrapper never hides the root cause.
- Keep observatory probe targets reachable to reduce connection-error noise.
When it happens
Trigger: Any outbound connection attempt made while probing an outbound (via session.TrackedConnectionError contexts) reports an error back to the collector — e.g. dial failure, TLS failure, or an upstream proxy refusing the connection. This wrapper becomes the head of that error chain.
Common situations: Almost always seen inside 'the outbound X is dead' log lines from the observatory; the useful information is the chained inner error (dial timeout, SOCKS rejection, TLS alert), not this wrapper text itself.
Related errors
- failed to produce report
- cannot finish connection
- cannot understand address
- cannot dial remote address
- outbound failed to relay connection
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/e5bc0b698e7d3200.
Report an issue: GitHub.