puppetlabs/puppet · error · Puppet::ParseError

%{label} of kind 'constant' requires a value

Error message

%{label} of kind 'constant' requires a value

What it means

A kind 'constant' attribute exists to hold a fixed value, so declaring one without a 'value' key is invalid — PAttribute#initialize raises this Puppet::ParseError on the else branch where a valueless attribute would end up as :undef, which is meaningless for a constant.

Source

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

      @kind = init_hash[KEY_KIND]
      if @kind == ATTRIBUTE_KIND_CONSTANT # final is implied
        if init_hash.include?(KEY_FINAL) && !@final
          # TRANSLATOR 'final => false' is puppet syntax and should not be translated
          raise Puppet::ParseError, _("%{label} of kind 'constant' cannot be combined with final => false") % { label: label }
        end

        @final = true
      end

      if init_hash.include?(KEY_VALUE)
        if @kind == ATTRIBUTE_KIND_DERIVED || @kind == ATTRIBUTE_KIND_GIVEN_OR_DERIVED
          raise Puppet::ParseError, _("%{label} of kind '%{kind}' cannot be combined with an attribute value") % { label: label, kind: @kind }
        end

        v = init_hash[KEY_VALUE]
        @value = v == :default ? v : TypeAsserter.assert_instance_of(nil, type, v) { "#{label} #{KEY_VALUE}" }
      else
        raise Puppet::ParseError, _("%{label} of kind 'constant' requires a value") % { label: label } if @kind == ATTRIBUTE_KIND_CONSTANT

        @value = :undef # Not to be confused with nil or :default
      end
    end

    def callable_type
      TYPE_ATTRIBUTE_CALLABLE
    end

    # @api public
    def eql?(o)
      super && @kind == o.kind && @value == (o.value? ? o.value : :undef)
    end

    # Returns the member as a hash suitable as an argument for constructor. Name is excluded
    # @return [Hash{String=>Object}] the hash
    # @api private
    def _pcore_init_hash

View on GitHub (pinned to e227c27540)

Solutions

  1. Add the required 'value' to the constant attribute: {'kind' => 'constant', 'value' => 'fixed'}.
  2. If no fixed value is intended, drop 'kind' => 'constant' and use a plain (or 'given') attribute.
  3. Add a structural check in codegen: kind 'constant' must always ship with a 'value' key.

Example fix

# before
{'type' => String, 'kind' => 'constant'}

# after
{'type' => String, 'kind' => 'constant', 'value' => 'fixed'}
Defensive patterns

Strategy: validation

Validate before calling

# Ruby — require value on constants before declaration
if h['kind'] == 'constant' && !h.key?('value')
  fail("constant attribute requires a value")
end

Type guard

def complete_constant?(h)
  h['kind'] != 'constant' || h.key?('value')
end

Prevention

When it happens

Trigger: An attribute hash {'type' => String, 'kind' => 'constant'} with no 'value' entry; commonly the result of setting the kind but forgetting the value, or of a default-stripping transform removing 'value' everywhere.

Common situations: Hand-editing type declarations; codegen that emits the kind but serializes the value separately (and omits it); refactors that drop 'value' while switching kinds.

Related errors


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