puppetlabs/puppet · error · Puppet::ParseError
%{label} of kind 'constant' cannot be combined with final =>
Error message
%{label} of kind 'constant' cannot be combined with final => false What it means
In a PObject type attribute, kind 'constant' implies final — a constant is fixed by definition. Declaring {'kind' => 'constant', 'final' => false} is contradictory, and PAttribute#initialize raises this Puppet::ParseError before final is force-set to true.
Source
Thrown at lib/puppet/pops/types/p_object_type.rb:306
# @param name [String] The name of the attribute
# @param container [PObjectType] The containing object type
# @param init_hash [Hash{String=>Object}] Hash containing attribute options
# @option init_hash [PAnyType] 'type' The attribute type (required)
# @option init_hash [Object] 'value' The default value, must be an instanceof the given `type` (optional)
# @option init_hash [String] 'kind' The attribute kind, matching #TYPE_ATTRIBUTE_KIND
# @api public
def initialize(name, container, init_hash)
super(name, container, TypeAsserter.assert_instance_of(nil, TYPE_ATTRIBUTE, init_hash) { "initializer for #{self.class.label(container, name)}" })
if name == Serialization::PCORE_TYPE_KEY || name == Serialization::PCORE_VALUE_KEY
raise Puppet::ParseError, _("The attribute '%{name}' is reserved and cannot be used") % { name: name }
end
@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
endView on GitHub (pinned to e227c27540)
Solutions
- Remove 'final' => false — a constant is always final.
- If the member must stay overridable/non-final, use a regular attribute with a 'value' instead of kind 'constant'.
- Validate generated type hashes against the documented option set per kind before declaring them.
Example fix
# before
{'type' => Float, 'kind' => 'constant', 'value' => 3.14, 'final' => false}
# after
{'type' => Float, 'kind' => 'constant', 'value' => 3.14} Defensive patterns
Strategy: validation
Validate before calling
# Ruby — validate an attribute hash before declaration
if h['kind'] == 'constant' && h.key?('final') && !h['final']
fail("constant implies final; remove final => false")
end Type guard
def consistent_finality?(h)
h['kind'] != 'constant' || !h.key?('final') || h['final'] == true
end Prevention
- Don't blanket-merge option defaults into attribute hashes; options are kind-specific.
- Keep constants minimal: type + kind + value only.
When it happens
Trigger: An attribute init hash that contains both 'kind' => 'constant' and 'final' => false, e.g. type T = Object[{'attributes' => {'pi' => {'type' => Float, 'kind' => 'constant', 'value' => 3.14, 'final' => false}}}].
Common situations: Hand-written or template-generated type hashes that merge defaults (final => false) into every attribute; converting a plain attribute to a constant while leftover option keys remain.
Related errors
- %{label} of kind '%{kind}' cannot be combined with an attrib
- %{label} of kind 'constant' requires a value
- expected %{label} to override an inherited %{feature_type},
- %{member} attempts to override %{label}
- %{member} attempts to override %{label} without having overr
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/6224c90bb13bb432.
Report an issue: GitHub.