gastownhall/beads · warning
epic %s has %d open child issue(s); close children first or
Error message
epic %s has %d open child issue(s); close children first or use --force to override
What it means
This error is returned by the EpicHasOpenChildren validator when attempting to close (or otherwise finalize) an epic that still has open child issues. The library refuses to close an epic whose work items are incomplete, and reports the count of open children. The user can either close the children first or explicitly override with a force flag.
Source
Thrown at internal/validation/issue.go:292
}
}
return fmt.Errorf("issue %s has type %s, expected one of: %v", id, issue.IssueType, allowed)
}
}
// EpicHasOpenChildren validates that an epic does not have open children.
// If the issue is an epic with open children, returns an error unless force is true.
// Non-epic issues pass through without validation.
func EpicHasOpenChildren(force bool, openChildCount int) IssueValidator {
return func(id string, issue *types.Issue) error {
if issue == nil || force {
return nil
}
if issue.IssueType != types.TypeEpic {
return nil
}
if openChildCount > 0 {
return fmt.Errorf("epic %s has %d open child issue(s); close children first or use --force to override", id, openChildCount)
}
return nil
}
}
// forUpdate returns a validator chain for update operations.
// Validates: issue exists and is not a template.
func forUpdate() IssueValidator {
return Chain(
Exists(),
NotTemplate(),
)
}
// forClose returns a validator chain for close operations.
// Validates: issue exists, is not a template, and is not pinned (unless force).
func forClose(force bool) IssueValidator {
return Chain(View on GitHub (pinned to 71377f2769)
Solutions
- List the epic's children and close all open ones, then retry closing the epic
- If the remaining children are genuinely obsolete, close them with an appropriate resolution first
- Use the force flag to close the epic anyway when intentionally abandoning open children (e.g. bd close <epic> --force)
- Re-parent or remove stale open children that no longer belong to the epic
Example fix
// before
bd.Close(epicID) // fails: 3 open children
// after
for _, child := range getChildren(epicID) {
if child.Status != types.StatusClosed {
bd.Close(child.ID)
}
}
bd.Close(epicID) Defensive patterns
Strategy: validation
Validate before calling
func canCloseEpic(epic *types.Issue, openChildCount int, force bool) bool {
return epic != nil && epic.IssueType == types.TypeEpic && (force || openChildCount == 0)
} Type guard
func epicWithOpenChildren(issue *types.Issue, openChildCount int) bool {
return issue != nil && issue.IssueType == types.TypeEpic && openChildCount > 0
} Try / catch
if err := closeIssue(epicID); err != nil {
if strings.Contains(err.Error(), "open child issue") {
return fmt.Errorf("close children of %s first or pass --force", epicID)
}
return err
} Prevention
- Close children before parents in any scripted teardown/close workflow
- Recount open children right before closing an epic (children may have been reopened)
- Only use --force when intentionally abandoning open work, and record why
- Periodically audit epics for orphaned or stale open children
When it happens
Trigger: Closing or validating an issue where issue.IssueType == types.TypeEpic and openChildCount > 0 and force is false. Non-epic issues pass through without validation; force=true bypasses the error.
Common situations: Bulk close scripts that close an epic without its children; a child was reopened after the epic was assumed done; dependency ordering mistakes where children are closed in the wrong order or partially; imported/migrated data with inconsistent parent-child states.
Related errors
- db: DependencySQLRepository.ValidateBlockingHierarchy: dep m
- add dep: hierarchy check: %w
- reparent: %s cannot be its own parent
- add deps[%d]: hierarchy check: %w
- applyGraph: node %q: planned blocking dependencies create a
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/45a20e50c1b5df5b.
Report an issue: GitHub.