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

  1. List the epic's children and close all open ones, then retry closing the epic
  2. If the remaining children are genuinely obsolete, close them with an appropriate resolution first
  3. Use the force flag to close the epic anyway when intentionally abandoning open children (e.g. bd close <epic> --force)
  4. 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

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


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