gastownhall/beads · error

invalid boolean value: %s

Error message

invalid boolean value: %s

What it means

Boolean fields (via buildBoolPredicate) accept only truthy/falsy literals: true/yes/1 and false/no/0 (case-insensitive). Any other value — including on/off, enabled, T/F, or a non-boolean token — triggers this error before the predicate is built.

Source

Thrown at internal/query/evaluator.go:1033

	case OpEquals:
		return func(i *types.Issue) bool { return i.SpecID == value }, nil
	case OpNotEquals:
		return func(i *types.Issue) bool { return i.SpecID != value }, nil
	default:
		return nil, fmt.Errorf("spec does not support %s operator", comp.Op.String())
	}
}

func (e *Evaluator) buildBoolPredicate(comp *ComparisonNode, getter func(*types.Issue) bool) (func(*types.Issue) bool, error) {
	val := strings.ToLower(comp.Value)
	var boolVal bool
	switch val {
	case "true", "yes", "1":
		boolVal = true
	case "false", "no", "0":
		boolVal = false
	default:
		return nil, fmt.Errorf("invalid boolean value: %s", comp.Value)
	}

	switch comp.Op {
	case OpEquals:
		return func(i *types.Issue) bool { return getter(i) == boolVal }, nil
	case OpNotEquals:
		return func(i *types.Issue) bool { return getter(i) != boolVal }, nil
	default:
		return nil, fmt.Errorf("boolean field does not support %s operator", comp.Op.String())
	}
}

// Evaluate is a convenience function that parses and evaluates a query string.
func Evaluate(query string) (*QueryResult, error) {
	return EvaluateAt(query, time.Now())
}

// EvaluateAt parses and evaluates a query string with a specific reference time.

View on GitHub (pinned to 71377f2769)

Solutions

  1. Rewrite the value as true/false, yes/no, or 1/0 (case-insensitive).
  2. Trim quotes and whitespace around the value in the query string.
  3. Check the %s in the message to see exactly what token was received — often a shell-escaping artifact.
  4. Fix UI/script generators to emit canonical true/false for boolean query fields.

Example fix

// before
bd list --query "pinned = on"
// after
bd list --query "pinned = true"   // or yes / 1
Defensive patterns

Strategy: validation

Validate before calling

var boolLiterals = map[string]bool{
	"true": true, "yes": true, "1": true,
	"false": false, "no": false, "0": false,
}
func validBoolValue(v string) bool {
	_, ok := boolLiterals[strings.ToLower(strings.TrimSpace(v))]
	return ok
}

Type guard

func asBoolLiteral(v string) (bool, bool) {
	b, ok := boolLiterals[strings.ToLower(strings.TrimSpace(v))]
	return b, ok
}

Try / catch

if err != nil && strings.Contains(err.Error(), "invalid boolean value") {
	return fmt.Errorf("use true/false, yes/no, or 1/0: %w", err)
}

Prevention

When it happens

Trigger: Queries like `pinned = on`, `blocked = enabled`, or `ready = "TRUE "` (with stray characters); a boolean comparison whose right-hand side does not normalize to one of the six accepted literals.

Common situations: SQL habits (bit values 1/0 are fine, but TRUE/FALSE spelled as T/F are not); config-file style on/off values; extra quotes or whitespace surviving shell escaping; passing numbers other than 1/0.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/1f33ffaa689fdfc1. Report an issue: GitHub.