opf/openproject · warning · WorkPackageHierarchyRelationsController::InvalidRelationType
Invalid relation type: #{type}
Error message
Invalid relation type: #{type} What it means
WorkPackageHierarchyRelationsController#relation_type only accepts the two hierarchy values Relation::TYPE_PARENT ('parent') and Relation::TYPE_CHILD ('child'); anything non-blank outside that set raises InvalidRelationType('Invalid relation type: #{type}'). This endpoint models the parent/child tree only — temporal/social relation kinds are rejected here.
Source
Thrown at app/controllers/work_package_hierarchy_relations_controller.rb:96
private
def create_hierarchy_association
if related_work_package.id.blank?
related_work_package.errors.add(:id, :blank)
return ServiceResult.failure(result: related_work_package)
end
if relation_type == "child"
set_relation(parent: @work_package, child: related_work_package)
else
set_relation(child: @work_package, parent: related_work_package)
end
end
def relation_type
type = params[:relation_type]
raise InvalidRelationType, "Missing relation_type parameter" if type.blank?
raise InvalidRelationType, "Invalid relation type: #{type}" unless type.in?([Relation::TYPE_PARENT, Relation::TYPE_CHILD])
type
end
def related_work_package
@related_work_package ||=
if params[:work_package][:id].present?
WorkPackage.visible.find(params[:work_package][:id])
else
WorkPackage.new
end
end
def set_relation(child:, parent:)
if allowed_to_set_parent?(child)
WorkPackages::UpdateService.new(
user: current_user,
model: child,View on GitHub (pinned to d9742c43f3)
Solutions
- Send exactly 'parent' or 'child' (lowercase) to this endpoint.
- Use the standard work package relations endpoint for all other relation types (follows, blocks, ...).
- Validate the value client-side against ['parent', 'child'] before submitting.
Example fix
# before
post path, params: { relation_type: 'follows', work_package: { id: other.id } }
# after
post path, params: { relation_type: 'child', work_package: { id: other.id } }
# 'follows' belongs to the general relations API instead Defensive patterns
Strategy: validation
Validate before calling
type = params[:relation_type].to_s type = type.downcase raise InvalidRelationType, type unless type.in?(%w[parent child])
Type guard
def hierarchy_relation_type?(value) value.is_a?(String) && value.in?([Relation::TYPE_PARENT, Relation::TYPE_CHILD]) end
Try / catch
begin relation_type rescue WorkPackageHierarchyRelationsController::InvalidRelationType => e render_error e.message, status: :unprocessable_entity end
Prevention
- Route non-hierarchy relation kinds (follows, blocks, precedes) to the general relations API by design.
- Normalize case before validating; document the endpoint's accepted set as exactly parent/child.
- Cover both invalid-type and missing-param cases in controller specs to lock the contract.
When it happens
Trigger: Posting relation_type='follows', 'blocks', 'precedes' etc. to the hierarchy relations endpoint — those belong to the general relations API, not the parent/child hierarchy endpoint; also custom strings or typos like 'Parent' (case-sensitive).
Common situations: Developers reuse one relations client for all relation kinds and route hierarchy types to the wrong endpoint; case mismatches ('Parent' vs 'parent'); older docs or snippets referencing an accepted set that later got narrowed.
Related errors
AI-assisted analysis of opf/openproject@d9742c43f3 (2026-08-21).
Data as JSON: /api/errors/8ea39d5465b66b91.
Report an issue: GitHub.