iOfficeAI/OfficeCLI · error · ArgumentException

Invalid boolean value: '{value}'. Expected true/false, yes/n

Error message

Invalid boolean value: '{value}'. Expected true/false, yes/no, 1/0, or on/off.

What it means

Thrown by IsTruthy when the value is a non-null, non-empty string that is not one of the recognized boolean tokens (true/false/yes/no/1/0/on/off). IsTruthy deliberately rejects ambiguous strings instead of guessing, so that a misspelled flag fails loudly rather than being treated as false. The comparison is case-insensitive and trims BOM/zero-width/format chars first.

Source

Thrown at src/officecli/Core/ParseHelpers.cs:311

        9 => "accent6",
        10 => "hlink",
        11 => "folHlink",
        _ => null,
    };

    /// <summary>
    /// Returns true if the value is a recognized boolean string and is truthy.
    /// Returns false for null, empty, or recognized falsy values ("false", "0", "no", "off").
    /// Throws <see cref="ArgumentException"/> for non-null values that are not recognized boolean strings.
    /// </summary>
    public static bool IsTruthy(string? value)
    {
        if (value == null) return false;
        return TrimInvisible(value).ToLowerInvariant() switch
        {
            "true" or "1" or "yes" or "on" => true,
            "false" or "0" or "no" or "off" or "" => false,
            _ => throw new ArgumentException(
                $"Invalid boolean value: '{value}'. Expected true/false, yes/no, 1/0, or on/off.")
        };
    }

    // R10: BOM (U+FEFF) and other zero-width / format chars are NOT in
    // char.IsWhiteSpace, so a plain Trim() leaves them in place. R8 added
    // Trim() but tests with `"true"` still threw. Use a stricter
    // predicate that also drops format/control chars.
    private static string TrimInvisible(string s)
    {
        return s.Trim().Trim(s_invisibleChars);
    }

    private static readonly char[] s_invisibleChars =
    {
        '', // BOM / zero-width no-break space
        '​', // zero-width space
        '‌', // zero-width non-joiner

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Use one of the canonical tokens: true/false, yes/no, 1/0, on/off.
  2. Map your custom vocabulary to a canonical token before calling IsTruthy.
  3. If unknown should mean false (not an error), catch ArgumentException or pre-check membership.

Example fix

// before
var enabled = ParseHelpers.IsTruthy(userInput); // userInput == "enabled"

// after
var map = new Dictionary<string,bool>(StringComparer.OrdinalIgnoreCase)
{
    ["enabled"]=true, ["disabled"]=false
};
var enabled = map.TryGetValue(userInput, out var b) ? b : ParseHelpers.IsTruthy(userInput);
Defensive patterns

Strategy: type-guard

Validate before calling

static readonly HashSet<string> BoolTokens = new(StringComparer.OrdinalIgnoreCase)
{ "true","false","yes","no","1","0","on","off" };
if (!BoolTokens.Contains(value)) value = "false";

Type guard

static bool IsRecognizedBool(string? v)
    => v != null && BoolTokens.Contains(v.Trim().ToLowerInvariant());

Try / catch

bool enabled;
try { enabled = ParseHelpers.IsTruthy(raw); }
catch (ArgumentException) { enabled = false; Console.Error.WriteLine($"unrecognized flag '{raw}'"); }

Prevention

When it happens

Trigger: Passing "maybe", "enable", "y", "t", or a localized yes/no. Also a value like "true " with non-breaking spaces would be handled by the strict trim, but unusual control chars combined with text could still miss.

Common situations: Flag values coming from user-typed CLI args ('y' instead of 'yes'); localized configs; values like 'enabled'/'disabled' from a different schema.

Related errors


AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13). Data as JSON: /api/errors/9ef291b939f79da9. Report an issue: GitHub.