{"record":{"id":"d25e1496ba6ab86b","repo":"felixse/FluentTerminal","slug":"red-node-value-was-not-a-real-number","errorCode":null,"errorMessage":"Red node value was not a real number","messagePattern":"Red node value was not a real number","errorType":"exception","errorClass":"ParseThemeException","httpStatus":null,"severity":"error","filePath":"FluentTerminal.App.Services/Implementation/ITermThemeParser.cs","lineNumber":112,"sourceCode":"                Magenta = GetColorString(themeDictionary[ITermThemeKeys.Ansi5Color]),\n                Cyan = GetColorString(themeDictionary[ITermThemeKeys.Ansi6Color]),\n                White = GetColorString(themeDictionary[ITermThemeKeys.Ansi7Color]),\n                BrightBlack = GetColorString(themeDictionary[ITermThemeKeys.Ansi8Color]),\n                BrightRed = GetColorString(themeDictionary[ITermThemeKeys.Ansi9Color]),\n                BrightGreen = GetColorString(themeDictionary[ITermThemeKeys.Ansi10Color]),\n                BrightYellow = GetColorString(themeDictionary[ITermThemeKeys.Ansi11Color]),\n                BrightBlue = GetColorString(themeDictionary[ITermThemeKeys.Ansi12Color]),\n                BrightMagenta = GetColorString(themeDictionary[ITermThemeKeys.Ansi13Color]),\n                BrightCyan = GetColorString(themeDictionary[ITermThemeKeys.Ansi14Color]),\n                BrightWhite = GetColorString(themeDictionary[ITermThemeKeys.Ansi15Color]),\n            };\n        }\n\n        private string GetColorString(PNode colorNode, byte alpha = Byte.MaxValue)\n        {\n            var dictionaryNode = colorNode as DictionaryNode ?? throw new ParseThemeException(\"Color node was not a dictionary\");\n\n            var red = dictionaryNode[ITermThemeColorKeys.RedComponent] as RealNode ?? throw new ParseThemeException(\"Red node value was not a real number\");\n            var green = dictionaryNode[ITermThemeColorKeys.GreenComponent] as RealNode ?? throw new ParseThemeException(\"Green node value was not a real number\");\n            var blue = dictionaryNode[ITermThemeColorKeys.BlueComponent] as RealNode ?? throw new ParseThemeException(\"Blue node value was not a real number\");\n\n            if (alpha == byte.MaxValue)\n            {\n                return $\"#{GetByteValue(red):X2}{GetByteValue(green):X2}{GetByteValue(blue):X2}\";\n            }\n            else\n            {\n                return $\"rgba({GetByteValue(red):G}, {GetByteValue(green):G}, {GetByteValue(blue):G}, {ToDoubleString(alpha)})\";\n            }\n        }\n\n        private byte GetByteValue(RealNode node)\n        {\n            var doubleValue = node.Value * Byte.MaxValue;\n\n            return Convert.ToByte(doubleValue);","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/felixse/FluentTerminal/blob/ba83ec485eea8d8ee65825711731300bee2e76ed/FluentTerminal.App.Services/Implementation/ITermThemeParser.cs#L94-L130","documentation":"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.","triggerScenarios":"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.","commonSituations":"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>.","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."],"exampleFix":"// before\nvar red = dictionaryNode[ITermThemeColorKeys.RedComponent] as RealNode ?? throw new ParseThemeException(\"Red node value was not a real number\");\n\n// after - accept integer or real nodes\nvar redNode = dictionaryNode[ITermThemeColorKeys.RedComponent];\ndouble redValue = redNode is RealNode r ? r.Value\n    : redNode is IntegerNode i ? i.Value / 255.0\n    : throw new ParseThemeException(\"Red node value was not a real number\");","handlingStrategy":"type-guard","validationCode":"bool IsRealComponent(PNode n) => n is PListNet.Nodes.RealNode;\n// Guard before casting:\nif (!(dictionaryNode[\"Red Component\"] is PListNet.Nodes.RealNode))\n    throw new ParseThemeException(\"Red Component must be a <real> in [0,1]\");","typeGuard":"static double? AsReal(PNode n) => n is PListNet.Nodes.RealNode r ? (double?)r.Value : null;","tryCatchPattern":"try { await parser.Import(name, stream); }\ncatch (ParseThemeException ex) when (ex.Message.Contains(\"Red node\"))\n{ notifyUser(\"Theme color channels must be real numbers (0.0-1.0).\"); }","preventionTips":["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."],"tags":["theme-parsing","plist","iterm","color","type-mismatch"],"backgroundTag":null,"analyzedSha":"ba83ec485eea8d8ee65825711731300bee2e76ed","analyzedAt":"2026-08-13T21:23:15.467Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}