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
- Avoid calling Close concurrently with in-flight persistence operations; sequence shutdown after all workers drain.
- Retry the operation: this state is usually transient; a subsequent With call will either use the new session or report the real connect error.
- 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
- Avoid concurrent Close()/Reconnect() while operations are in flight.
- Serialize lifecycle operations on the proxy through a single owner goroutine.
- Retry once with backoff — this state is typically a narrow race, not persistent.
- Report to maintainers if reproducible: a successful reconnect should always install a non-nil session.
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
- operation failed and reconnection failed: %w
- operation failed after reconnection: %w
- reconnection failed after %d retries, last error: %w
- operation %v is not supported
- offload node status is not supported
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/52832b0ebf10b8ed.
Report an issue: GitHub.