puppetlabs/puppet · error · Puppet::ParseError

%{member} attempts to override %{label} with a type that doe

Error message

%{member} attempts to override %{label} with a type that does not match

What it means

An overriding member's type must be assignable from the perspective of the inherited member: the parent's @type.assignable?(member.type) must hold, i.e. the child type must be a subtype (narrower or equal). Redeclaring with an unrelated or wider type raises this Puppet::ParseError.

Source

Thrown at lib/puppet/pops/types/p_object_type.rb:184

    # Checks if the given _member_ can override this member.
    #
    # @param member [PAnnotatedMember] the overriding member
    # @return [PAnnotatedMember] its argument
    # @raises [Puppet::ParseError] if the assertion fails
    # @api private
    def assert_can_be_overridden(member)
      unless instance_of?(member.class)
        raise Puppet::ParseError, _("%{member} attempts to override %{label}") % { member: member.label, label: label }
      end
      if @final && !(constant? && member.constant?)
        raise Puppet::ParseError, _("%{member} attempts to override final %{label}") % { member: member.label, label: label }
      end
      unless member.override?
        # TRANSLATOR 'override => true' is a puppet syntax and should not be translated
        raise Puppet::ParseError, _("%{member} attempts to override %{label} without having override => true") % { member: member.label, label: label }
      end
      unless @type.assignable?(member.type)
        raise Puppet::ParseError, _("%{member} attempts to override %{label} with a type that does not match") % { member: member.label, label: label }
      end

      member
    end

    def constant?
      false
    end

    # @return [Boolean] `true` if this feature cannot be overridden
    # @api public
    def final?
      @final
    end

    # @return [Boolean] `true` if this feature must override an inherited feature
    # @api public
    def override?

View on GitHub (pinned to e227c27540)

Solutions

  1. Make the child's type a subtype of the parent's: parent 'Any' -> child 'String' is fine; parent 'Integer' -> child 'Integer[1,10]' is fine.
  2. If you need a different contract, use a new member name instead of overriding.
  3. If you own the parent, widen the parent type deliberately (accepting the contract change for all subclasses).

Example fix

# before — Base: 'size' => Integer
type Sub = Object[{'parent' => 'Base', 'attributes' => {'size' => {'type' => String, 'override' => true}}}]

# after — narrow, don't change kind
type Sub = Object[{'parent' => 'Base', 'attributes' => {'size' => {'type' => Integer[1, 100], 'override' => true}}}]
Defensive patterns

Strategy: validation

Validate before calling

# Ruby — verify subtype relation before declaring an override
tc = Puppet::Pops::Types::TypeCalculator.singleton
fail("#{name}: #{child_type} is not assignable to inherited #{parent_type}") unless tc.assignable?(parent_type, child_type)

Type guard

def narrower_type?(parent_type, child_type)
  Puppet::Pops::Types::TypeCalculator.singleton.assignable?(parent_type, child_type)
end

Try / catch

begin
  Puppet::Pops::Types::PObjectType.new(name, hash)
rescue Puppet::ParseError => e
  raise CompileError, "override type mismatch: #{e.message} (child type must be a subtype)"
end

Prevention

When it happens

Trigger: Parent declares 'size' => Integer (or Numeric); child declares 'size' => {'type' => String, 'override' => true}; String is not assignable to Integer so the check fails. Widening (parent Integer, child Numeric) also fails.

Common situations: Assuming override => true permits any type change; attempting to widen a parent contract for 'flexibility'; narrowing in the wrong direction (parent String, child Enum when the enum values do not fit).

Related errors


AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21). Data as JSON: /api/errors/c0c0325d2f4a5ec5. Report an issue: GitHub.