{"record":{"id":"e89e2d72018ed01f","repo":"siyuan-note/siyuan","slug":"s-must-use-the-same-fields-in-light-and-dark-them","errorCode":null,"errorMessage":"%s must use the same fields in light and dark themes","messagePattern":"(.+?) must use the same fields in light and dark themes","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/inline_style.go","lineNumber":807,"sourceCode":"\nfunc normalizeInlineStyleThemePair(light, dark *InlineStyleTheme, description string) (normalizedLight,\n\tnormalizedDark *InlineStyleTheme, err error) {\n\tif light == nil || dark == nil {\n\t\treturn nil, nil, fmt.Errorf(\"%s must define light and dark themes\", description)\n\t}\n\tif normalizedLight, err = normalizeInlineStyleTheme(light); err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"invalid light theme of %s: %w\", description, err)\n\t}\n\tif normalizedDark, err = normalizeInlineStyleTheme(dark); err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"invalid dark theme of %s: %w\", description, err)\n\t}\n\tlightColor, lightBackground := normalizedLight.Color != \"\", normalizedLight.BackgroundColor != \"\"\n\tdarkColor, darkBackground := normalizedDark.Color != \"\", normalizedDark.BackgroundColor != \"\"\n\tif !lightColor && !lightBackground {\n\t\treturn nil, nil, fmt.Errorf(\"%s must define color or backgroundColor\", description)\n\t}\n\tif lightColor != darkColor || lightBackground != darkBackground {\n\t\treturn nil, nil, fmt.Errorf(\"%s must use the same fields in light and dark themes\", description)\n\t}\n\treturn normalizedLight, normalizedDark, nil\n}\n\nfunc normalizeHiddenBuiltinColorIndexes(indexes []int, field string) (ret []int, err error) {\n\tret = make([]int, 0, len(indexes))\n\tseen := make(map[int]struct{}, len(indexes))\n\tmaxIndex := maxBuiltinColorIndex\n\tif field == \"av\" {\n\t\tmaxIndex = neutralAVColorIndex\n\t}\n\tfor _, index := range indexes {\n\t\tif index < minBuiltinColorIndex || maxIndex < index {\n\t\t\treturn nil, fmt.Errorf(\"hidden builtin %s index [%d] must be between %d and %d\", field, index,\n\t\t\t\tminBuiltinColorIndex, maxIndex)\n\t\t}\n\t\tif _, exists := seen[index]; exists {\n\t\t\tcontinue","sourceCodeStart":789,"sourceCodeEnd":825,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/inline_style.go#L789-L825","documentation":"SiYuan inline-style color themes are stored as a paired light/dark theme, and both halves must fill in exactly the same set of fields. After normalization the code computes booleans for whether Color and BackgroundColor are present in each half; if the presence pattern differs between light and dark (e.g. light sets only Color, dark sets only BackgroundColor), the theme is rejected. This keeps rendering consistent when the user switches appearance mode.","triggerScenarios":"Calling any API that saves a custom inline style theme (normalizeInlineStyleThemes path in kernel/model/inline_style.go) with a light theme defining {color} and a dark theme defining {backgroundColor}, or one half empty while the other defines a field, or one half defining both fields and the other only one.","commonSituations":"Developers hand-crafting theme JSON for plugin/UI customization, migrating old single-theme configs to the paired format, or programmatically generating themes where the dark variant was built from a different template than the light variant.","solutions":["Ensure the dark theme defines exactly the same fields (color and/or backgroundColor) as the light theme.","If a field should be empty in dark mode, explicitly set it to \"\" in both halves rather than omitting it in only one.","Generate both theme halves from the same struct/template so their field sets cannot diverge."],"exampleFix":"// before\ntheme := &InlineStyleTheme{\n  Light: &InlineStyleThemeHalf{Color: \"#ff0000\"},\n  Dark:  &InlineStyleThemeHalf{BackgroundColor: \"#003300\"}, // mismatched fields\n}\n// after\ntheme := &InlineStyleTheme{\n  Light: &InlineStyleThemeHalf{Color: \"#ff0000\", BackgroundColor: \"\"},\n  Dark:  &InlineStyleThemeHalf{Color: \"#00ff00\", BackgroundColor: \"\"}, // same fields\n}","handlingStrategy":"validation","validationCode":"function themeFieldsMatch(light, dark) {\n  const has = (t, k) => Boolean(t && typeof t[k] === \"string\" && t[k] !== \"\");\n  return has(light, \"color\") === has(dark, \"color\") &&\n         has(light, \"backgroundColor\") === has(dark, \"backgroundColor\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always construct light and dark halves from the same template with both fields present (use \"\" for absent).","Write a small client-side parity check before saving any theme pair.","Never build the dark half from a different code path than the light half."],"tags":["validation","theme","inline-style","config"],"backgroundTag":"schema-validation-failed","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}