puppetlabs/puppet · error · Puppet::ParseError
attribute %{label}[%{key}] is defined as both a constant and
Error message
attribute %{label}[%{key}] is defined as both a constant and an attribute What it means
In an Object type definition, entries under constants are folded into the attribute map as constant-kind attributes. Before doing so, Puppet checks that no key appears in both constants and attributes; a Puppet::ParseError is raised because the two declarations would conflict over the same member name.
Source
Thrown at lib/puppet/pops/types/p_object_type.rb:742
end
param_type = POptionalType.new(param_type) unless param_type.is_a?(POptionalType)
type_param = PTypeParameter.new(key, self, KEY_TYPE => param_type, KEY_VALUE => param_value).assert_override(parent_type_params)
@type_parameters[key] = type_param
end
end
constants = init_hash[KEY_CONSTANTS]
attr_specs = init_hash[KEY_ATTRIBUTES]
if attr_specs.nil?
attr_specs = {}
else
# attr_specs might be frozen
attr_specs = attr_specs.to_h
end
unless constants.nil? || constants.empty?
constants.each do |key, value|
if attr_specs.include?(key)
raise Puppet::ParseError, _("attribute %{label}[%{key}] is defined as both a constant and an attribute") % { label: label, key: key }
end
attr_spec = {
# Type must be generic here, or overrides would become impossible
KEY_TYPE => TypeCalculator.infer(value).generalize,
KEY_VALUE => value,
KEY_KIND => ATTRIBUTE_KIND_CONSTANT
}
# Indicate override if parent member exists. Type check etc. will take place later on.
attr_spec[KEY_OVERRIDE] = parent_members.include?(key)
attr_specs[key] = attr_spec
end
end
unless attr_specs.empty?
@attributes = attr_specs.to_h do |key, attr_spec|
unless attr_spec.is_a?(Hash)
attr_type = TypeAsserter.assert_instance_of(nil, PTypeType::DEFAULT, attr_spec) { "attribute #{label}[#{key}]" }View on GitHub (pinned to e227c27540)
Solutions
- Pick one form: if the value should be settable per instance, keep it in attributes and delete it from constants; if fixed forever, keep only constants
- Run puppet parser validate or a catalog compile to catch it before deployment
Example fix
# before
type MyApp::Cfg = Object[{
attributes => { mode => String },
constants => { mode => 'read' }
}]
# after
type MyApp::Cfg = Object[{
attributes => { mode => String[1] }
}] Defensive patterns
Strategy: validation
Validate before calling
# before building the init hash / shipping a type definition
overlap = (constants.keys & attributes.keys)
raise "keys declared both constant and attribute: #{overlap.inspect}" unless overlap.empty? Try / catch
begin Puppet::Pops::Types::PObjectType.new(name, init_hash) rescue Puppet::ParseError => e raise unless e.message =~ /defined as both a constant and an attribute/ raise # e.message names the offending key; remove it from one block end
Prevention
- When promoting a constant to an attribute (or the reverse), delete the other block in the same edit
- Validate type definitions with puppet parser validate before deploy
- If generating type hashes programmatically, assert the attributes/constants key sets are disjoint
When it happens
Trigger: A type definition hash containing the same key in both blocks, e.g. attributes => { mode => String } and constants => { mode => 'read' }. Reachable from Puppet DSL type declarations, Ruby PObjectType init hashes, and pcore-loaded type definitions.
Common situations: Promoting a constant to a real attribute (or vice versa) and forgetting to delete the old block; merging type definitions programmatically; copy-paste between type definitions.
Related errors
- %{label} conflicts with attribute with the same name
- The attribute '%{name}' is reserved and cannot be used
- Initializer for class #{impl_class.name} does not match the
- Initializer for class #{impl_class.name} parameter '#{ip}' d
- reference to unresolved type '%{name}'
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/55dbd6e1b931e2f9.
Report an issue: GitHub.