{"record":{"id":"b3bf622a9f0a57d7","repo":"siyuan-note/siyuan","slug":"oidc-claim-rule-values-cannot-be-empty","errorCode":null,"errorMessage":"OIDC claim rule values cannot be empty","messagePattern":"OIDC claim rule values cannot be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/oidc.go","lineNumber":547,"sourceCode":"\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\n}\n\nfunc ValidateOIDCProviderConfiguration(ctx context.Context, config *conf.OIDC) error {\n\tif err := ValidateOIDCConfiguration(config); err != nil {","sourceCodeStart":529,"sourceCodeEnd":565,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/oidc.go#L529-L565","documentation":"Tenth check in ValidateOIDCConfiguration (kernel/model/oidc.go:547): a claim rule's Values slice contains an empty string. Each value is a literal to match against the claim, so blanks are rejected — they would otherwise match nothing meaningful.","triggerScenarios":"Adding a claim rule with a value row left blank in the UI, or a JSON rule like {Claim:'groups', Values:['admins','']}.","commonSituations":"Frontend allows trailing empty tag inputs; copy-pasting comma-separated values where a stray comma produced an empty element.","solutions":["Remove empty entries from each rule's Values list before saving.","Sanitize comma-separated input (split, trim, drop empties) on the client.","Re-run ValidateOIDCConfiguration to confirm."],"exampleFix":"// before\nrule.Values = []string{\"admins\", \"\"}\n// after — filter empties at the boundary\nrule.Values = nonEmpty([]string{\"admins\", \"\"}) // -> [\"admins\"]","handlingStrategy":"validation","validationCode":"cleaned := r.Values[:0]\nfor _, v := range r.Values {\n    if v = strings.TrimSpace(v); v != \"\" {\n        cleaned = append(cleaned, v)\n    }\n}\nr.Values = cleaned\nif len(r.Values) == 0 {\n    return errors.New(\"claim rule has no values\")\n}","typeGuard":"func noEmptyValues(r *conf.OIDCClaimRule) bool {\n    for _, v := range r.Values {\n        if strings.TrimSpace(v) == \"\" {\n            return false\n        }\n    }\n    return true\n}","tryCatchPattern":null,"preventionTips":["Trim and de-duplicate rule values on input.","Frontend should not submit placeholder empty tags."],"tags":["oidc","claim-rules","validation","input"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}