siyuan-note/siyuan · warning

wait for OIDC login transaction failed: %w

Error message

wait for OIDC login transaction failed: %w

What it means

The poll/callback request blocked on the transaction's Done channel and its context was cancelled first. The %w wraps ctx.Err(), typically context.DeadlineExceeded or context.Canceled, meaning the IdP callback had not arrived within the request deadline.

Source

Thrown at kernel/model/oidc.go:768

		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 &copy, 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 &copy, 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 251596fc0d)

Solutions

  1. Raise the long-poll/request timeout on the reverse proxy (>= 60s, more than a realistic consent delay).
  2. Have the user complete IdP consent promptly.
  3. For desktop/validate flows, simply retry the poll - the transaction state is preserved across poll requests.
Defensive patterns

Strategy: retry

Try / catch

// For desktop/validate polls, ctx cancellation is recoverable - just poll again.
tx, completed, err := claimOIDCTransaction(ctx, state, binding, allowDesktop)
if err != nil {
    if errors.Is(err, context.DeadlineExceeded) || errors.Is(err, context.Canceled) {
        // transient: retry the poll request, transaction is preserved
        return pollAgain
    }
}

Prevention

When it happens

Trigger: Long-poll endpoint where the user takes longer at the IdP than the request deadline allows; the HTTP/proxy context was cancelled (client disconnect, proxy timeout) before the callback completed the transaction.

Common situations: User idles on the IdP consent screen; reverse proxy with a short proxy_read_timeout that closes the long-poll; client aborts the poll request early.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/8ee0af86490bb30d. Report an issue: GitHub.