zed-industries/zed · error

invalid RGBA hex color: '{value}'. Expected #rgb, #rgba, #rr

Error message

invalid RGBA hex color: '{value}'. Expected #rgb, #rgba, #rrggbb, or #rrggbbaa

What it means

TryFrom<&str> for Rgba trims the input and splits once on '#'; the parse only succeeds when the result is exactly ("", hex), i.e. a pure '#'-prefixed literal. This first bail fires when there is no '#' at all, or when text precedes the '#'. CSS color functions and named colors are not supported by this parser.

Source

Thrown at crates/gpui/src/color.rs:237

            a: color.a,
        }
    }
}

impl TryFrom<&'_ str> for Rgba {
    type Error = anyhow::Error;

    fn try_from(value: &'_ str) -> Result<Self, Self::Error> {
        const RGB: usize = "rgb".len();
        const RGBA: usize = "rgba".len();
        const RRGGBB: usize = "rrggbb".len();
        const RRGGBBAA: usize = "rrggbbaa".len();

        const EXPECTED_FORMATS: &str = "Expected #rgb, #rgba, #rrggbb, or #rrggbbaa";
        const INVALID_UNICODE: &str = "invalid unicode characters in color";

        let Some(("", hex)) = value.trim().split_once('#') else {
            bail!("invalid RGBA hex color: '{value}'. {EXPECTED_FORMATS}");
        };

        let (r, g, b, a) = match hex.len() {
            RGB | RGBA => {
                let r = u8::from_str_radix(
                    hex.get(0..1).with_context(|| {
                        format!("{INVALID_UNICODE}: r component of #rgb/#rgba for value: '{value}'")
                    })?,
                    16,
                )?;
                let g = u8::from_str_radix(
                    hex.get(1..2).with_context(|| {
                        format!("{INVALID_UNICODE}: g component of #rgb/#rgba for value: '{value}'")
                    })?,
                    16,
                )?;
                let b = u8::from_str_radix(
                    hex.get(2..3).with_context(|| {

View on GitHub (pinned to f4178619ac)

Solutions

  1. Use one of the accepted literals: #rgb, #rgba, #rrggbb, #rrggbbaa
  2. If input is user-facing, strip non-hex prefixes and add the '#' before conversion
  3. Validate color strings at settings load time so the error names the offending key

Example fix

// before
let color = Rgba::try_from("1e1e2e")?; // no '#' -> bail

// after
let color = Rgba::try_from("#1e1e2e")?;
Defensive patterns

Strategy: validation

Validate before calling

fn is_valid_hex_color(value: &str) -> bool {
    let Some(hex) = value.trim().strip_prefix('#') else { return false };
    matches!(hex.len(), 3 | 4 | 6 | 8) && hex.chars().all(|c| c.is_ascii_hexdigit())
}

Type guard

fn is_hex_color(value: &str) -> bool {
    value.trim().starts_with('#') && value.trim().chars().skip(1).all(|c| c.is_ascii_hexdigit())
}

Try / catch

let color = Rgba::try_from(raw).with_context(|| format!("invalid color '{raw}' for setting '{key}'"))?;

Prevention

When it happens

Trigger: Converting strings like ff0000 (missing '#'), rgb(255,0,0), red, or 'color: #ff0000' into Rgba via theme or settings parsing, or any API that accepts color strings.

Common situations: Hand-edited theme or settings files using CSS syntax instead of hex; copy-pasted colors without the '#'; strings with labels or prefixes from other config formats.

Related errors


AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20). Data as JSON: /api/errors/83e6c6395e1ae1f0. Report an issue: GitHub.