felixse/FluentTerminal · error · ParseThemeException
Red node value was not a real number
Error message
Red node value was not a real number
What it means
Thrown by GetColorString when the "Red Component" child of a color dictionary cannot be cast to a RealNode. iTerm stores each channel as a floating-point value in [0,1] (a plist <real>). If the value was serialized as an <integer>, <string>, or <data> node, `as RealNode` returns null and ParseThemeException fires.
Source
Thrown at FluentTerminal.App.Services/Implementation/ITermThemeParser.cs:112
Magenta = GetColorString(themeDictionary[ITermThemeKeys.Ansi5Color]),
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
- Open the theme and confirm each "Red/Green/Blue Component" is a <real> in the 0.0-1.0 range (e.g. <real>0.5019607843137255</real>).
- Convert integer 0-255 values to reals by dividing by 255.0 if you must patch the file.
- Re-export the theme from a genuine iTerm2 install.
Example fix
// before
var red = dictionaryNode[ITermThemeColorKeys.RedComponent] as RealNode ?? throw new ParseThemeException("Red node value was not a real number");
// after - accept integer or real nodes
var redNode = dictionaryNode[ITermThemeColorKeys.RedComponent];
double redValue = redNode is RealNode r ? r.Value
: redNode is IntegerNode i ? i.Value / 255.0
: throw new ParseThemeException("Red node value was not a real number"); Defensive patterns
Strategy: type-guard
Validate before calling
bool IsRealComponent(PNode n) => n is PListNet.Nodes.RealNode;
// Guard before casting:
if (!(dictionaryNode["Red Component"] is PListNet.Nodes.RealNode))
throw new ParseThemeException("Red 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("Red node"))
{ notifyUser("Theme color channels must be real numbers (0.0-1.0)."); } Prevention
- Confirm each Red/Green/Blue Component is a <real> in 0.0-1.0, not an integer.
- When converting palettes, divide 0-255 integers by 255.0 before serializing.
- Re-export from iTerm2 if unsure.
When it happens
Trigger: A color dict's "Red Component" entry is present but typed as integer (e.g. 255 instead of 1.0), as a string ("1.0"), or as a Boolean. The lookup dictionaryNode[ITermThemeColorKeys.RedComponent] succeeds but the cast to RealNode fails.
Common situations: A plist editor or converter wrote color components as integers (0-255) instead of reals (0.0-1.0); the theme was authored for a tool that uses integer RGB; a hand-edit changed a <real>1.0</real> to <integer>255</integer>.
Related errors
- Green node value was not a real number
- Color node was not a dictionary
- Root node was not a dictionary.
AI-assisted analysis of felixse/FluentTerminal@ba83ec485e (2026-08-13).
Data as JSON: /api/errors/d25e1496ba6ab86b.
Report an issue: GitHub.