siyuan-note/siyuan · error
OIDC validation configuration is missing
Error message
OIDC validation configuration is missing
What it means
During activation of a validated OIDC configuration, the transaction record must still carry the candidate config snapshot (transaction.Config). If Config is nil the candidate configuration cannot be applied, so activateOIDCValidation aborts. This indicates internal state corruption or a transaction whose config was already consumed.
Solutions
- Recreate the validation transaction via OIDCValidateStart so a fresh candidate config snapshot is attached
- Ensure finishOIDCExchange ran for the validate flow and attached transaction.Config before activation
- Audit concurrent activation paths — guard against a second activation operating on the same transaction
- Check the transaction's Flow is oidcFlowValidate; a login-flow transaction has no candidate Config
Example fix
// before
transaction := &oidcTransaction{Flow: oidcFlowValidate, Binding: b, Completed: true, Success: true}
// after
transaction := &oidcTransaction{Flow: oidcFlowValidate, Binding: b, Completed: true, Success: true, Config: candidateConf, ConfigVersion: ver} Defensive patterns
Strategy: type-guard
Validate before calling
// ensure the validate transaction carries a candidate config before activating
if txn.Flow == oidcFlowValidate && txn.Config == nil { return ErrNoCandidateConfig } Type guard
func hasCandidateConfig(txn *oidcTransaction) bool {
return txn != nil && txn.Flow == oidcFlowValidate && txn.Config != nil
} Try / catch
ok, err := model.OIDCValidateActivate(pollToken, binding)
if err != nil && strings.Contains(err.Error(), "configuration is missing") {
return restartOIDCValidation() // rebuild transaction with attached config
} Prevention
- Always obtain transactions via OIDCValidateStart, never construct them by hand
- Complete the token exchange (finishOIDCExchange) before activation so Config is populated
- Avoid concurrent activations of the same transaction
When it happens
Trigger: Calling OIDCValidateActivate on a transaction that went through finishOIDCExchange as a non-validate flow, a transaction whose Config was already set to nil after a previous successful activation (Activated handled earlier, but ordering/nil paths in tests), or a manually constructed/corrupted transaction in tests TestActivateOIDCValidationAppliesCandidateOnce/RejectsChangedConfiguration/CancelOIDCValidationPreventsActivation.
Common situations: Race where activation runs twice concurrently and the second call sees a mutated transaction; custom test harness builds a validate-flow transaction without attaching Config; memory corruption after partial failure during exchange.
Related errors
- remote access requires at least one authentication method
- A public HTTPS OIDC redirect URL is required for remote…
- OIDC client ID is required
- OIDC configuration changed during validation
- OIDC configuration is missing
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/56b7ce9c911ef6b7.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/oidc.go:780
copy := *transaction
return ©, true
}
func activateOIDCValidation(pollToken, binding string) (activated bool, err error) {
oidcTransactions.Lock()
defer oidcTransactions.Unlock()
cleanupOIDCTransactionsLocked()
state := oidcTransactions.byPoll[pollToken]
transaction := oidcTransactions.byState[state]
if transaction == nil || transaction.Flow != oidcFlowValidate || transaction.Binding == "" ||
binding == "" || transaction.Binding != binding || !transaction.Completed || !transaction.Success {
return false, errors.New("OIDC validation transaction was not found or has expired")
}
if transaction.Activated {
return false, nil
}
if transaction.Config == nil {
return false, errors.New("OIDC validation configuration is missing")
}
configurationChanged, swapped := Conf.CompareAndSetOIDC(transaction.ConfigVersion, transaction.Config)
if !swapped {
deleteOIDCTransactionLocked(state)
return false, errors.New("OIDC configuration changed during validation")
}
transaction.Config = nil
transaction.Activated = true
return configurationChanged, nil
}
func cancelOIDCValidation(pollToken, binding string) bool {
oidcTransactions.Lock()
defer oidcTransactions.Unlock()
cleanupOIDCTransactionsLocked()
state := oidcTransactions.byPoll[pollToken]
transaction := oidcTransactions.byState[state]
if transaction == nil || transaction.Flow != oidcFlowValidate || transaction.Activated || transaction.Binding == "" ||View on GitHub (pinned to 9f775e8a12)