From 20dbe23a80bac9f2b6bade626842e8d1c7a8f3c6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 1 Nov 2025 13:24:23 +0000 Subject: [PATCH 1/4] Initial plan From 0428344daf40bc59469580fed4aad17296d6fc92 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 1 Nov 2025 13:30:18 +0000 Subject: [PATCH 2/4] Initial plan for fixing context deadline exceeded error message Co-authored-by: asmyasnikov <14202262+asmyasnikov@users.noreply.github.com> --- driver_test.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 driver_test.go diff --git a/driver_test.go b/driver_test.go new file mode 100644 index 000000000..b9515b3eb --- /dev/null +++ b/driver_test.go @@ -0,0 +1,19 @@ +package ydb + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +func TestOpen(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond) + defer cancel() + + time.Sleep(10 * time.Nanosecond) + + _, err := Open(ctx, "grpc://localhost:2136/local") + require.NoError(t, err) +} From abff6c5255eea93b2d5c7dcd1bf4ea926b61997d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 1 Nov 2025 13:35:25 +0000 Subject: [PATCH 3/4] Fix unreadable error when context deadline exceeded in ydb.Open Co-authored-by: asmyasnikov <14202262+asmyasnikov@users.noreply.github.com> --- driver.go | 4 ++++ driver_test.go | 9 +++++++-- internal/balancer/balancer.go | 4 ++++ retry/retry.go | 10 ++++++++++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/driver.go b/driver.go index 574624217..2202e6bb0 100644 --- a/driver.go +++ b/driver.go @@ -455,6 +455,10 @@ func (d *Driver) connect(ctx context.Context) error { if d.metaBalancer.balancer == nil { b, err := balancer.New(ctx, d.config, d.pool, d.discoveryOptions...) if err != nil { + // Don't wrap context errors with stack trace - let higher levels handle them + if xerrors.IsContextError(err) { + return err + } return xerrors.WithStackTrace(err) } d.metaBalancer.balancer = b diff --git a/driver_test.go b/driver_test.go index b9515b3eb..10273d91d 100644 --- a/driver_test.go +++ b/driver_test.go @@ -8,12 +8,17 @@ import ( "github.com/stretchr/testify/require" ) -func TestOpen(t *testing.T) { +func TestOpenWithExpiredContext(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond) defer cancel() time.Sleep(10 * time.Nanosecond) _, err := Open(ctx, "grpc://localhost:2136/local") - require.NoError(t, err) + require.Error(t, err) + require.ErrorIs(t, err, context.DeadlineExceeded) + require.Contains(t, err.Error(), "context deadline exceeded") + require.Contains(t, err.Error(), "Open(driver.go:") + // Verify that the error doesn't have multiple stack traces (no "retry failed on attempt") + require.NotContains(t, err.Error(), "retry failed") } diff --git a/internal/balancer/balancer.go b/internal/balancer/balancer.go index 1e3414389..ac81a654e 100644 --- a/internal/balancer/balancer.go +++ b/internal/balancer/balancer.go @@ -319,6 +319,10 @@ func New(ctx context.Context, driverConfig *config.Config, pool *conn.Pool, opts } else { // initialization of balancer state if err := b.clusterDiscovery(ctx); err != nil { + // Don't wrap context errors with stack trace - let higher levels handle them + if xerrors.IsContextError(err) { + return nil, err + } return nil, xerrors.WithStackTrace(err) } // run background discovering diff --git a/retry/retry.go b/retry/retry.go index 48f15dd41..807529eb2 100644 --- a/retry/retry.go +++ b/retry/retry.go @@ -267,6 +267,10 @@ func Retry(ctx context.Context, op retryOperation, opts ...Option) (finalErr err return nil, nil //nolint:nilnil }, opts...) if err != nil { + // Don't wrap context errors with stack trace - let higher levels handle them + if xerrors.IsContextError(err) { + return err + } return xerrors.WithStackTrace(err) } @@ -329,6 +333,12 @@ func RetryWithResult[T any](ctx context.Context, //nolint:revive,funlen defer func() { onDone(attempts, finalErr) }() + // Check if context is already done before entering retry loop + select { + case <-ctx.Done(): + return zeroValue, ctx.Err() + default: + } for { i++ attempts++ From 799ee6cc44ffe0b928c7855ca93135d2b9e70522 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 1 Nov 2025 13:40:26 +0000 Subject: [PATCH 4/4] Add test for context cancellation error message Co-authored-by: asmyasnikov <14202262+asmyasnikov@users.noreply.github.com> --- driver_test.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/driver_test.go b/driver_test.go index 10273d91d..e5d207e6d 100644 --- a/driver_test.go +++ b/driver_test.go @@ -22,3 +22,16 @@ func TestOpenWithExpiredContext(t *testing.T) { // Verify that the error doesn't have multiple stack traces (no "retry failed on attempt") require.NotContains(t, err.Error(), "retry failed") } + +func TestOpenWithCanceledContext(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + cancel() // Cancel immediately + + _, err := Open(ctx, "grpc://localhost:2136/local") + require.Error(t, err) + require.ErrorIs(t, err, context.Canceled) + require.Contains(t, err.Error(), "context canceled") + require.Contains(t, err.Error(), "Open(driver.go:") + // Verify that the error doesn't have multiple stack traces (no "retry failed on attempt") + require.NotContains(t, err.Error(), "retry failed") +}