gastownhall/beads · error

invalid closed time: %w

Error message

invalid closed time: %w

What it means

Wraps a parseTimeValue failure for the closed field: the value of a `closed` comparison could not be parsed as a relative time or absolute timestamp. The raw parser error is preserved with %w. Note that closed filters only make sense for issues that have been closed; parsing happens before any operator dispatch.

Source

Thrown at internal/query/evaluator.go:388

	case OpGreater:
		filter.UpdatedAfter = &t
	case OpGreaterEq:
		filter.UpdatedAfter = &t
	case OpLess:
		filter.UpdatedBefore = &t
	case OpLessEq:
		endOfDay := time.Date(t.Year(), t.Month(), t.Day(), 23, 59, 59, 999999999, t.Location())
		filter.UpdatedBefore = &endOfDay
	default:
		return fmt.Errorf("updated does not support %s operator", comp.Op.String())
	}
	return nil
}

func (e *Evaluator) applyClosedFilter(comp *ComparisonNode, filter *types.IssueFilter) error {
	t, err := e.parseTimeValue(comp)
	if err != nil {
		return fmt.Errorf("invalid closed time: %w", err)
	}
	switch comp.Op {
	case OpGreater:
		filter.ClosedAfter = &t
	case OpGreaterEq:
		filter.ClosedAfter = &t
	case OpLess:
		filter.ClosedBefore = &t
	case OpLessEq:
		endOfDay := time.Date(t.Year(), t.Month(), t.Day(), 23, 59, 59, 999999999, t.Location())
		filter.ClosedBefore = &endOfDay
	default:
		return fmt.Errorf("closed does not support %s operator", comp.Op.String())
	}
	return nil
}

func (e *Evaluator) applyStartedFilter(comp *ComparisonNode, filter *types.IssueFilter) error {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Use a supported duration form: `closed > 30d`, `closed < 24h`
  2. Use an absolute date/time accepted by ParseRelativeTime (e.g. `2026-08-01` or RFC3339)
  3. Check the wrapped cause in the error chain to identify the exact parse problem

Example fix

// before
bd list 'closed > one month ago'
// after
bd list 'closed > 30d'
Defensive patterns

Strategy: validation

Validate before calling

// Validate the closed value parses before running the query
func validClosedValue(v string) bool {
	if regexp.MustCompile(`^\d+[dhmsw]$`).MatchString(v) {
		return true
	}
	_, err := timeparsing.ParseRelativeTime(v, time.Now())
	return err == nil
}
if !validClosedValue(value) { return fmt.Errorf("bad closed value: %q", value) }

Type guard

func isParseableTime(v string) bool {
	_, err := timeparsing.ParseRelativeTime(v, time.Now())
	return err == nil
}

Try / catch

if err := eval.Eval(node); err != nil {
	if strings.Contains(err.Error(), "invalid closed time") {
		// fix the value (e.g. 'one month ago' -> '30d') and retry
	}
}

Prevention

When it happens

Trigger: Queries like `closed > 30x`, `closed < ''`, `closed >= nonsense` — any `closed <op> value` whose value fails duration (parseDurationAgo) or relative-time (ParseRelativeTime) parsing.

Common situations: Reporting scripts with malformed interpolated dates; units the duration parser rejects; users typing prose dates (`closed > last month`) where only compact forms work; running closed filters in environments where relative keywords differ.

Related errors


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