XTLS/Xray-core · error · errors.Error
cannot finish connection
Error message
cannot finish connection
What it means
Thrown in app/observatory/observer.go:154 as the outer wrapper returned from DialContext when the task.Run closure (parse + dial) returned any error. It is the boundary translation between Xray's task error and Go's net.Dial return, so its Base chain contains either 'cannot understand address' or 'cannot dial remote address' plus the root cause.
Source
Thrown at app/observatory/observer.go:154
},
DialContext: func(ctx context.Context, network string, addr string) (net.Conn, error) {
var connection net.Conn
taskErr := task.Run(ctx, func() error {
// MUST use Xray's built in context system
dest, err := v2net.ParseDestination(network + ":" + addr)
if err != nil {
return errors.New("cannot understand address").Base(err)
}
trackedCtx := session.TrackedConnectionError(o.ctx, errorCollectorForRequest)
conn, err := tagged.Dialer(trackedCtx, o.dispatcher, dest, outbound)
if err != nil {
return errors.New("cannot dial remote address ", dest).Base(err)
}
connection = conn
return nil
})
if taskErr != nil {
return nil, errors.New("cannot finish connection").Base(taskErr)
}
return connection, nil
},
TLSHandshakeTimeout: time.Second * 5,
}
httpClient := &http.Client{
Transport: &httpTransport,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
Jar: nil,
Timeout: time.Second * 5,
}
var GETTime time.Duration
err := task.Run(o.ctx, func() error {
startTime := time.Now()
probeURL := "https://www.google.com/generate_204"
if o.config.ProbeUrl != "" {View on GitHub (pinned to 7d214f8b09)
Solutions
- Inspect err.Base() to find whether it was an address parse issue or a dial failure, then follow the corresponding fix.
- Verify the outbound server and its streamSettings.
- Confirm the probe URL is well-formed.
Defensive patterns
Strategy: try-catch
Try / catch
// always unwrap: the wrapper has no independent information
if err != nil {
root := err
for errors.Unwrap(root) != nil { root = errors.Unwrap(root) }
handleByRootCause(root)
} Prevention
- Never branch on the 'cannot finish connection' text itself; branch on the chained cause.
- Log with %v under a multi-error-aware formatter.
When it happens
Trigger: Always produced together with errors 45/46: any failure of the inner parse-or-dial task surfaces to Go's http.Transport as 'cannot finish connection'. This message is the envelope; the real cause is one level down in Base().
Common situations: Appears in the middle of probe failure chains; by itself it only tells you the probe connection setup failed, and users should always read the chained error.
Related errors
- underlying connection error
- cannot dial remote address
- failed to produce report
- cannot understand address
- outbound failed to relay connection
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/95700abd00c327f7.
Report an issue: GitHub.