siyuan-note/siyuan · warning
wait for OIDC login transaction failed
Error message
wait for OIDC login transaction failed: %w
What it means
When a transaction has already been claimed (e.g. the desktop app polling via poll token and the callback both claiming it), the second claimant waits on transaction.Done for the flow to complete. If the caller's context is cancelled or times out first, this error wraps the context error via %w. It signals that the wait was aborted, not that the login itself failed.
Solutions
- Retry the claim/wait with a fresh context if the login is still in progress
- Increase the client-side request timeout so the poll waits at least as long as oidcTransactionTimeout
- Ensure the UI keeps the connection alive until the transaction completes or expires
Example fix
// before ctx := context.Background() // or a short-lived request ctx // after: give the wait enough headroom ctx, cancel := context.WithTimeout(context.Background(), oidcTransactionTimeout) defer cancel()
Defensive patterns
Strategy: retry
Try / catch
tx, done, err := claimOIDCTransaction(ctx, state, binding, false)
if err != nil {
var ctxErr error
if errors.As(err, &ctxErr) || strings.Contains(err.Error(), "context") {
// wait aborted: retry with a longer-lived context if login may still complete
}
} Prevention
- Set client request timeouts >= oidcTransactionTimeout for poll requests
- Keep the polling connection open until completion
- Avoid cancelling or refreshing the waiting tab during login
When it happens
Trigger: A second concurrent claim of the same state (poll endpoint vs callback) whose request context is cancelled — HTTP client disconnect, request timeout, or explicit context cancellation before the other claimant completes the transaction.
Common situations: Desktop poll request aborted by the user closing the window; frontend fetch timeout shorter than the login takes; user refreshing/cancelling while another tab waits.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
Related errors
- A loopback OIDC redirect URL is required for local access
- A public HTTPS OIDC redirect URL is required for remote…
- AI editor request timeout
- AI editor stream idle timeout
- capability execution was cancelled before it started
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/8ee0af86490bb30d.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/oidc.go:712
return nil, false, errors.New("OIDC configuration changed during login")
}
if !(allowDesktopWithoutBinding && (transaction.Flow == oidcFlowDesktop || transaction.Flow == oidcFlowValidate)) &&
(binding == "" || binding != transaction.Binding) {
oidcTransactions.Unlock()
return nil, false, errors.New("OIDC login binding does not match")
}
if !transaction.Claimed {
transaction.Claimed = true
copy := *transaction
oidcTransactions.Unlock()
return ©, false, nil
}
done := transaction.Done
oidcTransactions.Unlock()
select {
case <-ctx.Done():
return nil, false, fmt.Errorf("wait for OIDC login transaction failed: %w", ctx.Err())
case <-done:
}
oidcTransactions.Lock()
defer oidcTransactions.Unlock()
transaction = oidcTransactions.byState[state]
if transaction == nil || !transaction.Completed {
return nil, false, errors.New("OIDC login transaction was not found or has expired")
}
copy := *transaction
return ©, true, nil
}
func completeOIDCTransaction(state string, success bool, message string) {
oidcTransactions.Lock()
defer oidcTransactions.Unlock()
transaction := oidcTransactions.byState[state]
if transaction == nil {View on GitHub (pinned to 9f775e8a12)