{"record":{"id":"343e080ed4c4aa0d","repo":"siyuan-note/siyuan","slug":"unsupported-oidc-claim-rule-operator","errorCode":null,"errorMessage":"Unsupported OIDC claim rule operator","messagePattern":"Unsupported OIDC claim rule operator","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/oidc.go","lineNumber":543,"sourceCode":"\t\tissuer, err := url.Parse(config.IssuerURL)\n\t\tif err != nil || issuer.Host == \"\" || issuer.User != nil || issuer.RawQuery != \"\" || issuer.Fragment != \"\" ||\n\t\t\t(issuer.Scheme != \"https\" && !util.IsLocalHostname(issuer.Hostname())) {\n\t\t\treturn errors.New(\"OIDC issuer URL must use HTTPS unless it is a loopback address\")\n\t\t}\n\t}\n\tif config.Provider != conf.OIDCProviderCustom && config.Provider != conf.OIDCProviderGoogle &&\n\t\tconfig.Provider != conf.OIDCProviderMicrosoft && config.Provider != conf.OIDCProviderGitHub {\n\t\treturn errors.New(\"Unsupported OIDC provider\")\n\t}\n\tif !config.AllowAll && len(config.ClaimRules) == 0 {\n\t\treturn errors.New(\"OIDC login requires at least one claim rule when Allow all users is disabled\")\n\t}\n\tfor _, rule := range config.ClaimRules {\n\t\tif rule == nil || rule.Claim == \"\" || len(rule.Values) == 0 {\n\t\t\treturn errors.New(\"OIDC claim rules must include a claim and at least one value\")\n\t\t}\n\t\tif rule.Operator != conf.OIDCClaimOperatorEquals && rule.Operator != conf.OIDCClaimOperatorContains {\n\t\t\treturn errors.New(\"Unsupported OIDC claim rule operator\")\n\t\t}\n\t\tfor _, value := range rule.Values {\n\t\t\tif value == \"\" {\n\t\t\t\treturn errors.New(\"OIDC claim rule values cannot be empty\")\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc ValidateOIDCMobileConfiguration(config *conf.OIDC) error {\n\tif err := ValidateOIDCConfiguration(config); err != nil {\n\t\treturn err\n\t}\n\tif config.Provider == conf.OIDCProviderGoogle {\n\t\treturn errors.New(\"Google does not support the fixed SiYuan mobile OIDC callback URI\")\n\t}\n\treturn nil","sourceCodeStart":525,"sourceCodeEnd":561,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/oidc.go#L525-L561","documentation":"Ninth check in ValidateOIDCConfiguration (kernel/model/oidc.go:543): a claim rule's Operator is neither OIDCClaimOperatorEquals nor OIDCClaimOperatorContains. SiYuan only supports these two match semantics, so any other operator value is rejected.","triggerScenarios":"Saving a claim rule with a custom/wrong operator string (e.g. '==', 'in', 'regex'); a future-version rule downgraded to an unsupported constant.","commonSituations":"Hand-edited JSON using arbitrary operator strings; a plugin writing rules with its own operator vocabulary; UI bug submitting a raw enum label.","solutions":["Use 'equals' or 'contains' (the OIDCClaimOperator* constants) for every rule.","Re-open the rule in the settings UI and pick one of the two supported operators.","After fixing, re-validate with ValidateOIDCConfiguration."],"exampleFix":"// before\nrule.Operator = \"in\"\n// after\nrule.Operator = conf.OIDCClaimOperatorEquals","handlingStrategy":"validation","validationCode":"switch r.Operator {\ncase conf.OIDCClaimOperatorEquals, conf.OIDCClaimOperatorContains:\ndefault:\n    return fmt.Errorf(\"unsupported operator: %%s\", r.Operator)\n}","typeGuard":"func validOperator(o conf.OIDCClaimOperator) bool {\n    return o == conf.OIDCClaimOperatorEquals || o == conf.OIDCClaimOperatorContains\n}","tryCatchPattern":null,"preventionTips":["Always write operator constants, not literals.","Frontend dropdowns should be bound to the two valid values only."],"tags":["oidc","claim-rules","operator","validation"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}