{"record":{"id":"50199721a5f67672","repo":"v2rayA/v2rayA","slug":"tuic-connection-ends","errorCode":null,"errorMessage":"tuic connection ends","messagePattern":"tuic connection ends","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"core/hint/proxy/tuic/outbound.go","lineNumber":147,"sourceCode":"\n\tdestAddr := fmt.Sprintf(\"%s:%d\", destination.Address.String(), destination.Port.Value())\n\n\tconn, err := c.dialer.DialContext(ctx, \"tcp\", destAddr)\n\tif err != nil {\n\t\treturn errors.New(\"tuic: failed to dial destination\").Base(err)\n\t}\n\tdefer conn.Close()\n\n\tpostRequest := func() error {\n\t\treturn xray_buf.Copy(link.Reader, xray_buf.NewWriter(outboundConnWriter(conn)))\n\t}\n\tgetResponse := func() error {\n\t\treturn xray_buf.Copy(xray_buf.NewReader(outboundConnReader(conn)), link.Writer)\n\t}\n\n\tresponseDoneAndCloseWriter := task.OnSuccess(getResponse, task.Close(link.Writer))\n\tif err := task.Run(ctx, postRequest, responseDoneAndCloseWriter); err != nil {\n\t\treturn errors.New(\"tuic connection ends\").Base(err)\n\t}\n\n\treturn nil\n}\n\n// outboundConnReader/Writer wraps outbound_netproxy.Conn to expose io.Reader/Writer for xray's buf.\ntype outboundConn struct {\n\tc outbound_netproxy.Conn\n}\n\nfunc outboundConnReader(c outbound_netproxy.Conn) io.Reader { return &outboundConn{c} }\nfunc outboundConnWriter(c outbound_netproxy.Conn) io.Writer { return &outboundConn{c} }\nfunc (n *outboundConn) Read(b []byte) (int, error)          { return n.c.Read(b) }\nfunc (n *outboundConn) Write(b []byte) (int, error)         { return n.c.Write(b) }\n\nfunc init() {\n\tcommon.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {\n\t\treturn NewClient(ctx, config.(*ClientConfig))","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/v2rayA/v2rayA/blob/71e5442fc548c05680ee55eae943e6c0afe9ac51/core/hint/proxy/tuic/outbound.go#L129-L165","documentation":"Client.Process runs two concurrent tasks — posting the request (upload) and reading the response (download) — via task.Run. If either task errors, the combined failure is wrapped as \"tuic connection ends\" with the original error as base. It signals the proxied connection terminated abnormally rather than a clean close.","triggerScenarios":"task.Run(ctx, postRequest, responseDoneAndCloseWriter) returns non-nil: the remote side reset the connection mid-transfer, a read/write timeout fired, or the context was cancelled while copying data.","commonSituations":"Server closes the connection abruptly (crash, restart, idle timeout); unstable network path dropping packets; client context cancelled by an upstream deadline; protocol handshake failure surfaced during copy.","solutions":["Read the .Base(err) cause: io.EOF on one direction may be benign; net.OpError reset/timeout indicates network trouble.","Increase idle timeouts on client and server if long-lived connections are being dropped.","Check TUIC server logs and availability; retry transient network failures.","Ensure the request context isn't cancelled prematurely by an overly tight deadline."],"exampleFix":"// before\nif err := task.Run(ctx, postRequest, responseDoneAndCloseWriter); err != nil {\n    return errors.New(\"tuic connection ends\").Base(err)\n}\n\n// after\nif err := task.Run(ctx, postRequest, responseDoneAndCloseWriter); err != nil {\n    if errors.Is(errors.Unwrap(err), io.EOF) { return nil }\n    return errors.New(\"tuic connection ends\").Base(err)\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := task.Run(ctx, postRequest, responseDoneAndCloseWriter); err != nil {\n    if errors.Is(err, io.EOF) || context.Canceled == errors.Unwrap(err) {\n        return nil // benign close\n    }\n    var nErr net.Error\n    if errors.As(errors.Unwrap(err), &nErr) && nErr.Timeout() {\n        // reconnect/retry the tuic session\n    }\n    return errors.New(\"tuic connection ends\").Base(err)\n}","preventionTips":["Keep-alive/idle timeouts aligned between client and server.","Monitor server restarts that abort in-flight tuic sessions.","Retry idempotent transfers on transient stream errors."],"tags":["tuic","connection-reset","stream-copy"],"backgroundTag":"connection-reset-by-peer","analyzedSha":"71e5442fc548c05680ee55eae943e6c0afe9ac51","analyzedAt":"2026-09-05T20:04:37.459Z","contentChangedAt":"2026-09-05T20:04:37.459Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}