spectreconsole/spectre.console · error · InvalidOperationException
A background color has already been set.
Error message
A background color has already been set.
What it means
After `on` (background mode), a background color was already set and a second background color is encountered. Only one background color is allowed per tag.
Source
Thrown at src/Spectre.Console.Ansi/AnsiMarkupTagParser.cs:10
namespace Spectre.Console;
internal static class AnsiMarkupTagParser
{
public static (Style Style, Link? Link) Parse(string text)
{
var result = Parse(text, out var error);
if (error != null)
{
throw new InvalidOperationException(error);
}
return result ?? throw new InvalidOperationException("Could not parse style.");
}
public static bool TryParse(string text, [NotNullWhen(true)] out (Style Style, Link?)? result)
{
result = Parse(text, out _);
return result != null;
}
private static (Style Style, Link? Link)? Parse(string text, out string? error)
{
var effectiveDecoration = (Decoration?)null;
var effectiveForeground = (Color?)null;
var effectiveBackground = (Color?)null;
var effectiveLink = (string?)null;
View on GitHub (pinned to 0acc92fada)
Solutions
- Provide exactly one background color after `on`
- Move any additional foreground color into a separate nested tag
- Use `default` to leave a slot unset
Example fix
// before
AnsiMarkup.Parse("[red on blue green]text[/]");
// after
AnsiMarkup.Parse("[red on blue]text[/]");
// or nest if both colors are wanted as foreground/background:
AnsiMarkup.Parse("[blue][red on green]text[/][/]"); Defensive patterns
Strategy: validation
Validate before calling
// Ensure at most one color token follows `on`:
public static int BackgroundColorCount(string tag)
{
var onIdx = tag.IndexOf(" on ", StringComparison.OrdinalIgnoreCase);
if (onIdx < 0) return 0;
return tag[(onIdx + 4)..].Split(' ', StringSplitOptions.RemoveEmptyEntries)
.Count(p => ColorTable.GetColor(p) != null || Regex.IsMatch(p, "^#[0-9A-Fa-f]{6}$"));
} Try / catch
try { AnsiMarkup.Parse(markup); }
catch (InvalidOperationException ex) when (ex.Message == "A background color has already been set.")
{ /* keep only the first background color */ } Prevention
- Remember a second `on` does not switch back to foreground
- Use exactly one background color per tag
- Nest tags to layer additional colors
When it happens
Trigger: Two colors after `on`, e.g. `[on blue red]`, `[red on blue green]`, or `[on 1 2]`.
Common situations: Forgetting that everything after the first `on` is background; multiple `on` keywords don't switch back to foreground (they're no-ops), so a later color is still treated as background.
Related errors
- Color number must be greater than or equal to 0 (was {number
- Color number must be less than or equal to 255 (was {number}
- Could not find color '{part}'.
- Could not find color or style '{part}'.
- A foreground color has already been set.
AI-assisted analysis of spectreconsole/spectre.console@0acc92fada (2026-08-13).
Data as JSON: /api/errors/7e2fe2d4644c4c8a.
Report an issue: GitHub.