gastownhall/beads · error

close reason is terse (%d chars); aim for 20+ characters des

Error message

close reason is terse (%d chars); aim for 20+ characters describing what was done

What it means

ValidateCloseReason rejects close reasons shorter than 20 characters as too terse. The function trims whitespace, then enforces a minimum length so close summaries actually describe the work performed. This complements the empty/default check and is enforced by validation.on-close config.

Source

Thrown at internal/validation/template.go:211

		}
		remaining = append(remaining, m)
	}
	if len(remaining) == 0 {
		return nil
	}
	templateErr.Missing = remaining
	return templateErr
}

// ValidateCloseReason checks if a close reason meets minimum quality standards.
// Returns nil if the reason is acceptable. Used by validation.on-close config.
func ValidateCloseReason(reason string) error {
	reason = strings.TrimSpace(reason)
	if reason == "" || strings.EqualFold(reason, "closed") {
		return fmt.Errorf("close reason is empty or default; provide a summary of what was done")
	}
	if len(reason) < 20 {
		return fmt.Errorf("close reason is terse (%d chars); aim for 20+ characters describing what was done", len(reason))
	}
	return nil
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Write a reason of at least 20 characters describing what was done, e.g. "Closed: implemented X, tested with Y"
  2. Expand terse script templates to include a short sentence about the change
  3. Adjust validation.on-close thresholds only if 20 chars is genuinely too strict for your workflow

Example fix

// before
bd close bd-42 --reason "done"
// after
bd close bd-42 --reason "Done: rewrote collector to batch events; 3 tests added"
Defensive patterns

Strategy: validation

Validate before calling

if len(strings.TrimSpace(reason)) < 20 {
    return fmt.Errorf("reason must be 20+ chars, got %d", len(strings.TrimSpace(reason)))
}

Try / catch

if err := validation.ValidateCloseReason(reason); err != nil {
    if strings.HasPrefix(err.Error(), "close reason is terse") { reason = expandReason(reason) }
    return err
}

Prevention

When it happens

Trigger: Closing an issue with a reason like "done", "ok", "fixed" — any trimmed string of fewer than 20 characters reaching ValidateCloseReason.

Common situations: One-word close messages typed interactively; scripts using placeholder reasons like "wip done"; agents summarizing too briefly.

Related errors


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