{"record":{"id":"733da79eb595f0c7","repo":"siyuan-note/siyuan","slug":"oidc-configuration-changed-during-provider-discove","errorCode":null,"errorMessage":"OIDC configuration changed during provider discovery","messagePattern":"OIDC configuration changed during provider discovery","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"kernel/model/oidc.go","lineNumber":665,"sourceCode":"\tif oidcProviders.version != version {\n\t\toidcProviders.version = version\n\t\toidcProviders.items = map[string]*oidc_provider.Provider{}\n\t}\n\tif provider := oidcProviders.items[key]; provider != nil {\n\t\toidcProviders.Unlock()\n\t\treturn provider, nil\n\t}\n\toidcProviders.Unlock()\n\tdiscoveryContext, cancel := context.WithTimeout(ctx, oidcProviderTimeout)\n\tdefer cancel()\n\tprovider, err := oidc_provider.New(discoveryContext, Conf.GetOIDC(), redirectURL)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\toidcProviders.Lock()\n\tdefer oidcProviders.Unlock()\n\tif oidcProviders.version != version || oidcConfigurationVersion(Conf.GetOIDC()) != version {\n\t\treturn nil, errors.New(\"OIDC configuration changed during provider discovery\")\n\t}\n\tif existing := oidcProviders.items[key]; existing != nil {\n\t\treturn existing, nil\n\t}\n\tif len(oidcProviders.items) >= oidcProviderCacheMax {\n\t\toidcProviders.items = map[string]*oidc_provider.Provider{}\n\t}\n\toidcProviders.items[key] = provider\n\treturn provider, nil\n}\n\nfunc newOIDCTransaction(input *oidcStartInput, binding, clientIP, redirectURL string) (*oidcTransaction, error) {\n\tstate, err := secureRandomToken(32)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tnonce, err := secureRandomToken(32)\n\tif err != nil {","sourceCodeStart":647,"sourceCodeEnd":683,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/oidc.go#L647-L683","documentation":"getOIDCProvider releases the lock to run OIDC discovery (a network call capped at oidcProviderTimeout = 10s). After re-acquiring the lock it checks that the cached config version still matches the live one; if an admin saved OIDC settings during discovery, the freshly-discovered provider is discarded to avoid serving a provider built from stale config.","triggerScenarios":"Admin saves OIDC settings while a login or validation flow is mid-discovery; rapid successive config edits racing with new logins.","commonSituations":"Operator iterates on OIDC config while users are actively logging in; load/CI tests that reconfigure OIDC concurrently with login traffic.","solutions":["Retry /api/system/oidc/start - the new config will be discovered and cached.","Stop editing OIDC settings while logins are in flight.","If it persists, confirm only one admin/process is writing OIDC config."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Retry start once; the new config version will be discovered and cached.\nvar provider *oidc_provider.Provider\nfor attempt := 0; attempt < 2; attempt++ {\n    provider, err = getOIDCProvider(ctx, redirectURL)\n    if err == nil {\n        break\n    }\n    if !strings.Contains(err.Error(), \"configuration changed during provider discovery\") {\n        break\n    }\n}","preventionTips":["Do not edit OIDC settings while users are logging in.","Serialize config writes - only one admin/process at a time.","Treat discovery as retryable; surface a friendly 'try again' to the user."],"tags":["oidc","concurrency","configuration","race-condition","discovery"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}