netbirdio/netbird · warning
session extend already in progress
Error message
session extend already in progress
What it means
The client allows exactly one ExtendAuthSession in flight: beginExtend refuses to create a second context while extendCancel is non-nil, because the underlying PKCE flow binds a fixed loopback port that a concurrent flow could not acquire. The error is reported to the second call's ErrListener; the first flow is unaffected.
Source
Thrown at client/android/session.go:264
if err != nil {
log.Warnf("session warning event with unparsable deadline: %v", err)
continue
}
lead, err := sessionwatch.ParseLeadMinutes(meta[sessionwatch.MetaSessionLeadMinutes])
if err != nil {
// Informational only — the deadline above is what drives the UI.
lead = 0
}
listener.OnSessionExpiring(deadline.Unix(), int64(lead),
meta[sessionwatch.MetaSessionFinal] == "true")
}
}
func (c *Client) beginExtend() (context.Context, error) {
c.extendMu.Lock()
defer c.extendMu.Unlock()
if c.extendCancel != nil {
return nil, fmt.Errorf("session extend already in progress")
}
ctx, cancel := context.WithCancel(context.Background())
c.extendCancel = cancel
return ctx, nil
}
func (c *Client) endExtend() {
c.extendMu.Lock()
defer c.extendMu.Unlock()
if c.extendCancel != nil {
c.extendCancel()
c.extendCancel = nil
}
}
func (c *Client) extendAuthSession(ctx context.Context, urlOpener URLOpener, isAndroidTV bool) error {
cfg, cfgPath, cc := c.authSnapshot()
if cfg == nil || cc == nil {View on GitHub (pinned to 93e97f4bf1)
Solutions
- Wait for the first flow's OnSuccess/OnError before starting another
- If the user abandoned the browser, call CancelExtendAuthSession first, then start the new flow
- Disable the renew action in the UI while a flow is in flight
Example fix
// before
renewBtn.setOnClickListener { client.ExtendAuthSession(opener, false, listener) } // double-tap → second call errors
// after: cancel the abandoned flow before re-starting
renewBtn.setOnClickListener {
if (extendInFlight) client.CancelExtendAuthSession()
extendInFlight = true
client.ExtendAuthSession(opener, false, listener)
} Defensive patterns
Strategy: validation
Validate before calling
// Track flow state in the UI and cancel before re-starting if (extendInFlight) client.CancelExtendAuthSession() extendInFlight = true client.ExtendAuthSession(opener, isTV, listener)
Type guard
fun canStartExtend(inFlight: Boolean): Boolean = !inFlight // gate the button on this
Try / catch
// In the ErrListener of ExtendAuthSession
func (l *extendListener) OnError(err error) {
if strings.Contains(err.Error(), "session extend already in progress") {
// benign: another flow is running; either wait for its result or cancel it first
return
}
l.show(err)
} Prevention
- Disable the renew button while a flow is in flight; re-enable on OnSuccess/OnError
- Call CancelExtendAuthSession whenever the user abandons the browser — the PKCE port stays bound otherwise
- Model the extend flow as single-instance in the UI, mirroring the client's own guard
When it happens
Trigger: Calling ExtendAuthSession again while a previous one is still waiting for the user to complete the browser step — a double-tap on the renew button, or a retry after the user abandoned the browser without calling CancelExtendAuthSession (which keeps the loopback port bound for the full flow timeout).
Common situations: UI that does not disable the renew button while a flow is in flight; user backs out of the browser and immediately retries; stale tap events queued during the browser round-trip.
Related errors
- failed to get OAuth flow: %v
- getting a request OAuth flow info failed: %v
- waiting for browser login failed: %v
- engine is not running
- management client is not initialised
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/20d1b8ceedc9db94.
Report an issue: GitHub.