felixse/FluentTerminal · error · ParseThemeException

Green node value was not a real number

Error message

Green node value was not a real number

What it means

Thrown by GetColorString when the "Green Component" child of a color dictionary is not a RealNode. Identical mechanism to the Red Component check: iTerm expects a plist <real> in [0,1]; an integer/string/bool value makes the `as RealNode` cast null and raises ParseThemeException.

Source

Thrown at FluentTerminal.App.Services/Implementation/ITermThemeParser.cs:113

                Cyan = GetColorString(themeDictionary[ITermThemeKeys.Ansi6Color]),
                White = GetColorString(themeDictionary[ITermThemeKeys.Ansi7Color]),
                BrightBlack = GetColorString(themeDictionary[ITermThemeKeys.Ansi8Color]),
                BrightRed = GetColorString(themeDictionary[ITermThemeKeys.Ansi9Color]),
                BrightGreen = GetColorString(themeDictionary[ITermThemeKeys.Ansi10Color]),
                BrightYellow = GetColorString(themeDictionary[ITermThemeKeys.Ansi11Color]),
                BrightBlue = GetColorString(themeDictionary[ITermThemeKeys.Ansi12Color]),
                BrightMagenta = GetColorString(themeDictionary[ITermThemeKeys.Ansi13Color]),
                BrightCyan = GetColorString(themeDictionary[ITermThemeKeys.Ansi14Color]),
                BrightWhite = GetColorString(themeDictionary[ITermThemeKeys.Ansi15Color]),
            };
        }

        private string GetColorString(PNode colorNode, byte alpha = Byte.MaxValue)
        {
            var dictionaryNode = colorNode as DictionaryNode ?? throw new ParseThemeException("Color node was not a dictionary");

            var red = dictionaryNode[ITermThemeColorKeys.RedComponent] as RealNode ?? throw new ParseThemeException("Red node value was not a real number");
            var green = dictionaryNode[ITermThemeColorKeys.GreenComponent] as RealNode ?? throw new ParseThemeException("Green node value was not a real number");
            var blue = dictionaryNode[ITermThemeColorKeys.BlueComponent] as RealNode ?? throw new ParseThemeException("Blue node value was not a real number");

            if (alpha == byte.MaxValue)
            {
                return $"#{GetByteValue(red):X2}{GetByteValue(green):X2}{GetByteValue(blue):X2}";
            }
            else
            {
                return $"rgba({GetByteValue(red):G}, {GetByteValue(green):G}, {GetByteValue(blue):G}, {ToDoubleString(alpha)})";
            }
        }

        private byte GetByteValue(RealNode node)
        {
            var doubleValue = node.Value * Byte.MaxValue;

            return Convert.ToByte(doubleValue);
        }

View on GitHub (pinned to ba83ec485e)

Solutions

  1. Verify every "Green Component" value is a <real> in 0.0-1.0 range.
  2. Normalize integer values by dividing by 255.0 when patching.
  3. Re-export from iTerm2 for a known-good structure.

Example fix

// before
var green = dictionaryNode[ITermThemeColorKeys.GreenComponent] as RealNode ?? throw new ParseThemeException("Green node value was not a real number");

// after - coerce integer or real
double greenValue = greenNode is RealNode r ? r.Value
    : greenNode is IntegerNode i ? i.Value / 255.0
    : throw new ParseThemeException("Green node value was not a real number");
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(dictionaryNode["Green Component"] is PListNet.Nodes.RealNode))
    throw new ParseThemeException("Green Component must be a <real> in [0,1]");

Type guard

static double? AsReal(PNode n) => n is PListNet.Nodes.RealNode r ? (double?)r.Value : null;

Try / catch

try { await parser.Import(name, stream); }
catch (ParseThemeException ex) when (ex.Message.Contains("Green node"))
{ notifyUser("Theme green channel must be a real number (0.0-1.0)."); }

Prevention

When it happens

Trigger: A color dict has "Green Component" typed as <integer> (e.g. 128) or as a <string> rather than a <real>. Occurs for any color entry processed by GetColorString (Background, Foreground, Cursor, all 16 Ansi colors).

Common situations: Converter tool emitted integer RGB for the green channel; manual edit replaced a <real> with a whole number; theme sourced from a non-iTerm palette format.

Related errors


AI-assisted analysis of felixse/FluentTerminal@ba83ec485e (2026-08-13). Data as JSON: /api/errors/65b2d278ce1b8794. Report an issue: GitHub.