argoproj/argo-workflows · error

no active session after reconnection

Error message

no active session after reconnection

What it means

After a network error triggered a reconnection inside With, the reconnection succeeded but sp.sess was still nil when re-read under the lock, so the retried operation cannot run. This is a narrow internal race/degenerate state of SessionProxy between reconnectIfStale and the session re-fetch.

Source

Thrown at util/sqldb/session.go:299

	if err == nil {
		return nil
	}

	// If it's not a network error or inside a tx do not retry
	if !sp.isNetworkError(err) || sp.insideTransaction {
		return err
	}

	if reconnectErr := sp.reconnectIfStale(ctx, sess); reconnectErr != nil {
		return fmt.Errorf("operation failed and reconnection failed: %w", reconnectErr)
	}

	sp.mu.RLock()
	sess = sp.sess
	sp.mu.RUnlock()

	if sess == nil {
		return fmt.Errorf("no active session after reconnection")
	}

	if retryErr := fn(sess); retryErr != nil {
		return fmt.Errorf("operation failed after reconnection: %w", retryErr)
	}

	return nil
}

// reconnectIfStale reconnects only if the current session is still the
// same one that produced the error. If another goroutine already
// reconnected (sp.sess != staleSess), this is a no-op.
func (sp *SessionProxy) reconnectIfStale(ctx context.Context, staleSess db.Session) error {
	sp.mu.Lock()
	defer sp.mu.Unlock()
	if sp.sess != staleSess {
		return nil
	}

View on GitHub (pinned to 35bff19146)

Solutions

  1. Avoid calling Close concurrently with in-flight persistence operations; sequence shutdown after all workers drain.
  2. Retry the operation: this state is usually transient; a subsequent With call will either use the new session or report the real connect error.
  3. If reproducible, file/inspect the connect() implementation to ensure a successful connect always sets sp.sess non-nil.

Example fix

// before
err := proxy.With(ctx, fn) // "no active session after reconnection"
// after
err := proxy.With(ctx, fn)
if err != nil && strings.Contains(err.Error(), "no active session after reconnection") {
	time.Sleep(time.Second)
	err = proxy.With(ctx, fn) // transient race; retry once
}
Defensive patterns

Strategy: retry

Validate before calling

if proxy.Session() == nil {
	return errors.New("session not established; call Reconnect first")
}

Try / catch

err := proxy.With(ctx, fn)
if err != nil && strings.Contains(err.Error(), "no active session after reconnection") {
	time.Sleep(backoff)
	err = proxy.With(ctx, fn) // transient race; retry
}

Prevention

When it happens

Trigger: With retries after reconnectIfStale returned nil, but the re-read sp.sess is nil — e.g. a concurrent Reconnect/Close nulled or closed the session between the reconnect completing and the retry, or the connect path reported success but did not install a session.

Common situations: Concurrent shutdown (Close) racing with in-flight retry logic; concurrent goroutines reconnecting the same proxy; bugs in custom connect() implementations wired into the proxy.

Related errors


AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03). Data as JSON: /api/errors/52832b0ebf10b8ed. Report an issue: GitHub.