libnyanpasu/clash-nyanpasu · error

Invalid theme color: {}

Error message

Invalid theme color: {}

What it means

patch_verge validates the optional theme_color field before applying an IVerge patch. If theme_color is set, non-empty, and not a strict '#RRGGBB' hex string (7 chars, '#' prefix, ASCII hex digits only — see is_hex_color in backend/tauri/src/config/nyanpasu/mod.rs:10), the patch is rejected with anyhow::bail and nothing is written.

Source

Thrown at backend/tauri/src/feat.rs:352

            Config::clash().data().save_config()?;
            Ok(rebuilt)
        }
        Err(err) => {
            Config::clash().discard();
            Err(err)
        }
    }
}

/// 修改verge的配置
/// 一般都是一个个的修改
pub async fn patch_verge(client: crate::client::NyanpasuClient, patch: IVerge) -> Result<()> {
    // Validate theme_color if it's being updated
    if let Some(ref theme_color) = patch.theme_color
        && !theme_color.is_empty()
        && !crate::config::nyanpasu::is_hex_color(theme_color)
    {
        anyhow::bail!("Invalid theme color: {}", theme_color);
    }

    Config::verge().draft().patch_config(patch.clone());
    let tun_mode = patch.enable_tun_mode;
    let auto_launch = patch.enable_auto_launch;
    let system_proxy = patch.enable_system_proxy;
    let proxy_bypass = patch.system_proxy_bypass;
    let language = patch.language;
    let log_level = patch.app_log_level;
    let log_max_files = patch.max_log_files;
    let enable_tray_selector = patch.clash_tray_selector;
    let enable_tray_text = patch.enable_tray_text;
    let tray_menu_mode = patch.tray_menu_mode;
    let network_statistic_widget = patch.network_statistic_widget;
    let res = || async move {
        let service_mode = patch.enable_service_mode;
        if let Some(service_mode) = service_mode {
            log::debug!(target: "app", "change service mode to {}", service_mode);

View on GitHub (pinned to f7dbce2997)

Solutions

  1. Normalize the value to a 7-character '#RRGGBB' hex string (uppercase or lowercase digits both pass) before calling patch_verge
  2. If the color is not a plain hex (named color, rgb(), 8-digit hex), convert it: expand #RGB to #RRGGBB and drop the alpha bytes
  3. Trim whitespace and confirm length is exactly 7 with a leading '#' before sending the patch
  4. If no theme change is intended, send patch with theme_color: None (or omit the field) instead of an empty or placeholder string

Example fix

// before
client.patch_verge(IVerge { theme_color: Some("#fff".into()), ..patch }).await?;
// after
let color = "#fff";
let normalized = if color.len() == 4 && color.starts_with('#') {
    format!("#{0}{0}{1}{1}{2}{2}", &color[1..2], &color[2..3], &color[3..4])
} else { color.to_string() };
assert!(crate::config::nyanpasu::is_hex_color(&normalized));
client.patch_verge(IVerge { theme_color: Some(normalized), ..patch }).await?;
Defensive patterns

Strategy: validation

Validate before calling

pub fn valid_theme_color(color: &str) -> bool {
    color.len() == 7 && color.starts_with('#') && color[1..].chars().all(|c| c.is_ascii_hexdigit())
}
// call site
if let Some(c) = &patch.theme_color {
    if !c.is_empty() && !valid_theme_color(c) { return Err(anyhow!("Invalid theme color: {}", c)); }
}

Type guard

fn as_valid_theme_color(color: &Option<String>) -> Option<&str> {
    color.as_deref().filter(|c| !c.is_empty() && c.len() == 7 && c.starts_with('#') && c[1..].chars().all(|c| c.is_ascii_hexdigit()))
}

Try / catch

match client.patch_verge(patch).await {
    Err(e) if e.to_string().starts_with("Invalid theme color") => {
        log::warn("theme_color rejected, reverting to default");
        client.patch_verge(IVerge { theme_color: None, ..patch }).await?;
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling patch_verge (e.g. via the patch_verge_entrypoint Tauri command) with patch.theme_color = Some(value) where value is not exactly 7 characters of the form #RRGGBB: e.g. 'blue', '#fff', '#GGGGGG', 'rgb(255,0,0)', '#ffffff ' (trailing space), or a full-length '#RRGGBBAA' string.

Common situations: Frontend color pickers emitting lowercase names or 3-digit hex; a user typing a color manually into a config UI; switching from a theme that stored alpha-extended hex (#RRGGBBAA) or named colors; a migration/import importing an old verge config with non-hex theme_color; locale-sensitive input adding whitespace.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08). Data as JSON: /api/errors/19a6152a11b581f3. Report an issue: GitHub.