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

  1. Send exactly 'parent' or 'child' (lowercase) to this endpoint.
  2. Use the standard work package relations endpoint for all other relation types (follows, blocks, ...).
  3. 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

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.