siyuan-note/siyuan · error
OIDC login transaction capacity reached
Error message
OIDC login transaction capacity reached
What it means
storeOIDCTransaction refuses new entries once the in-memory store holds oidcTransactionMax (512) transactions server-wide. This bounds memory; expired entries are only reaped lazily on the next store/claim call via cleanupOIDCTransactionsLocked.
Source
Thrown at kernel/model/oidc.go:711
if err != nil {
return nil, err
}
}
return &oidcTransaction{State: state, Nonce: nonce, CodeVerifier: verifier, PollToken: pollToken, Binding: binding,
ClientIP: clientIP,
Flow: input.Flow, RedirectURL: redirectURL, To: input.To, ConfigVersion: oidcConfigurationVersion(Conf.GetOIDC()), RememberMe: input.RememberMe,
ExpiresAt: time.Now().Add(oidcTransactionTimeout), Done: make(chan struct{})}, nil
}
func storeOIDCTransaction(transaction *oidcTransaction) error {
oidcTransactions.Lock()
defer oidcTransactions.Unlock()
cleanupOIDCTransactionsLocked()
if transaction.Done == nil {
transaction.Done = make(chan struct{})
}
if len(oidcTransactions.byState) >= oidcTransactionMax {
return errors.New("OIDC login transaction capacity reached")
}
perIP, perBinding := 0, 0
for _, candidate := range oidcTransactions.byState {
if candidate.Completed {
continue
}
if transaction.ClientIP != "" && candidate.ClientIP == transaction.ClientIP {
perIP++
}
if transaction.Binding != "" && candidate.Binding == transaction.Binding {
perBinding++
}
}
if perIP >= oidcTransactionPerIP || perBinding >= oidcTransactionPerBind {
return errors.New("too many pending OIDC login transactions")
}
oidcTransactions.byState[transaction.State] = transaction
if transaction.PollToken != "" {View on GitHub (pinned to 251596fc0d)
Solutions
- Wait roughly 10 minutes for expiry reap to free slots.
- Restart the kernel to clear the in-memory transaction store if urgent.
- Investigate source IPs/bindings - if a single source dominates, it is likely abuse and should be rate-limited at the edge.
Defensive patterns
Strategy: retry
Try / catch
// On capacity errors, back off and retry; the lazy reaper frees slots as transactions expire.
if err := storeOIDCTransaction(tx); err != nil {
if strings.Contains(err.Error(), "capacity reached") {
time.Sleep(retryBackoff)
// retry start, or surface 'service busy, retry shortly'
}
} Prevention
- Rate-limit /api/system/oidc/start at the edge per IP.
- Ensure clients complete the IdP callback promptly rather than abandoning flows.
- Monitor pending transaction count and alert well below 512.
When it happens
Trigger: A burst of /api/system/oidc/start calls (legitimate or abusive) that outpaces the 10-minute transaction expiry reap; clients that start login but never complete the IdP callback.
Common situations: Bot or scanner hitting the start endpoint; many users behind one NAT starting flows simultaneously; abandoned browser tabs each holding a transaction.
Related errors
- OIDC configuration changed during provider discovery
- too many pending OIDC login transactions
- OIDC configuration changed during login
- wait for OIDC login transaction failed: %w
- OIDC configuration changed during validation
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/5e0ba046af45fdee.
Report an issue: GitHub.