siyuan-note/siyuan · error
OIDC state is missing
Error message
OIDC state is missing
What it means
claimOIDCTransaction validates the OAuth2 state parameter during the callback exchange. If the state query parameter is empty, there is no way to look up the login transaction, so it fails immediately with this error. The state parameter is mandatory for CSRF protection in the OIDC authorization-code flow.
Solutions
- Start a fresh OIDC login from SiYuan rather than reusing or manually editing the callback URL
- Check reverse-proxy/CDN rules so they do not strip query parameters from the callback path
- If a custom IdP is in use, ensure it echoes the state parameter back in the redirect
Example fix
// before: proxy strips query proxy_pass http://kernel; # with query rewriting removing ?state=... // after: preserve query args in the proxy proxy_pass http://kernel; # ensure $args / $is_args$args are preserved on /api/system/oidc/callback
Defensive patterns
Strategy: validation
Validate before calling
if r.URL.Query().Get("state") == "" {
http.Error(w, "state parameter is required", http.StatusBadRequest)
return
} Prevention
- Never hand-edit the callback URL; always follow the IdP redirect
- Verify reverse proxy/CDN preserves query strings on /api/system/oidc/callback
- Confirm the IdP echoes the state parameter back
When it happens
Trigger: OIDCCallback or OIDCMobileCallback receives a request whose query string lacks the state parameter (state is empty string); a hand-crafted or truncated callback URL.
Common situations: The IdP drops the state parameter; the callback URL was copied/edited manually; a misconfigured redirect URL strips query parameters at the proxy.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- A loopback OIDC redirect URL is required for local access
- A public HTTPS OIDC redirect URL is required for remote…
- decode OIDC claims failed
- Desktop OIDC login requires a loopback listener
- discover OIDC provider failed
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/47089e6b3dbee950.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/oidc.go:682
}
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 != "" {
oidcTransactions.byPoll[transaction.PollToken] = transaction.State
}
return nil
}
func claimOIDCTransaction(ctx context.Context, state, binding string,
allowDesktopWithoutBinding bool) (*oidcTransaction, bool, error) {
if state == "" {
return nil, false, errors.New("OIDC state is missing")
}
oidcTransactions.Lock()
cleanupOIDCTransactionsLocked()
transaction := oidcTransactions.byState[state]
if transaction == nil {
oidcTransactions.Unlock()
return nil, false, errors.New("OIDC login transaction was not found or has expired")
}
if transaction.ConfigVersion != oidcConfigurationVersion(Conf.GetOIDC()) {
deleteOIDCTransactionLocked(state)
oidcTransactions.Unlock()
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")
}View on GitHub (pinned to 9f775e8a12)