we-promise/sure · error · Category::Merger::UnauthorizedCategoryError
Cannot merge a category with subcategories into a subcategor
Error message
Cannot merge a category with subcategories into a subcategory
What it means
Category::Merger#validate_reparenting! blocks merges where the target is itself a subcategory (parent_id present) and at least one source category has children (family.categories.exists?(parent_id: source.id)). Reparenting a parent-with-subcategories under a subcategory would push an entire subtree below a leaf, which the merger does not support.
Source
Thrown at app/models/category/merger.rb:56
def validate_category_belongs_to_family!(category, label)
return if category&.family_id == family.id
raise UnauthorizedCategoryError, "#{label} does not belong to this family"
end
def validate_hierarchy!
target_ancestor_ids = ancestor_ids_for(target_category)
return unless source_categories.any? { |source| target_ancestor_ids.include?(source.id) }
raise UnauthorizedCategoryError, "A parent category cannot be merged into its own subcategory"
end
def validate_reparenting!
return if target_category.parent_id.blank?
return unless source_categories.any? { |source| family.categories.exists?(parent_id: source.id) }
raise UnauthorizedCategoryError, "Cannot merge a category with subcategories into a subcategory"
end
def ancestor_ids_for(category)
ids = []
seen_ids = Set.new
current = category
while current&.parent_id.present? && seen_ids.exclude?(current.parent_id)
ids << current.parent_id
seen_ids << current.parent_id
current = family.categories.find_by(id: current.parent_id)
end
ids
end
def merge_budget_categories(source)
family.budget_categories.where(category_id: source.id).find_each do |source_budget_category|View on GitHub (pinned to e69894adb9)
Solutions
- Merge into a top-level (parentless) target category instead of a subcategory
- First move or merge away the source's subcategories, then retry the original merge
- Surface the rule in the UI: disable subcategory targets whenever any selected source has children
Defensive patterns
Strategy: validation
Validate before calling
target_is_subcategory = target_category.parent_id.present? sources_have_children = family.categories.exists?(parent_id: source_categories.map(&:id)) unsafe = target_is_subcategory && sources_have_children
Prevention
- Default merge targets to top-level categories
- Flatten or relocate a source's subcategories before merging it into a leaf
- Disable subcategory targets in the picker when any source has children
When it happens
Trigger: Choosing a subcategory as the merge target while any selected source category still has its own subcategories: target.parent_id is set AND a category with parent_id == source.id exists in the family.
Common situations: Reorganizing category trees by collapsing a broad category into a more specific leaf; merge tools that allow arbitrary targets without checking source subtrees.
Related errors
- A parent category cannot be merged into its own subcategory
- #{label} does not belong to this family
- No categories available for auto-categorization
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/01bbadc44983edaf.
Report an issue: GitHub.