{"record":{"id":"6224c90bb13bb432","repo":"puppetlabs/puppet","slug":"label-of-kind-constant-cannot-be-combined-wit","errorCode":null,"errorMessage":"%{label} of kind 'constant' cannot be combined with final => false","messagePattern":"%(.+?) of kind 'constant' cannot be combined with final => false","errorType":"exception","errorClass":"Puppet::ParseError","httpStatus":null,"severity":"error","filePath":"lib/puppet/pops/types/p_object_type.rb","lineNumber":306,"sourceCode":"\n    # @param name [String] The name of the attribute\n    # @param container [PObjectType] The containing object type\n    # @param init_hash [Hash{String=>Object}] Hash containing attribute options\n    # @option init_hash [PAnyType] 'type' The attribute type (required)\n    # @option init_hash [Object] 'value' The default value, must be an instanceof the given `type` (optional)\n    # @option init_hash [String] 'kind' The attribute kind, matching #TYPE_ATTRIBUTE_KIND\n    # @api public\n    def initialize(name, container, init_hash)\n      super(name, container, TypeAsserter.assert_instance_of(nil, TYPE_ATTRIBUTE, init_hash) { \"initializer for #{self.class.label(container, name)}\" })\n      if name == Serialization::PCORE_TYPE_KEY || name == Serialization::PCORE_VALUE_KEY\n        raise Puppet::ParseError, _(\"The attribute '%{name}' is reserved and cannot be used\") % { name: name }\n      end\n\n      @kind = init_hash[KEY_KIND]\n      if @kind == ATTRIBUTE_KIND_CONSTANT # final is implied\n        if init_hash.include?(KEY_FINAL) && !@final\n          # TRANSLATOR 'final => false' is puppet syntax and should not be translated\n          raise Puppet::ParseError, _(\"%{label} of kind 'constant' cannot be combined with final => false\") % { label: label }\n        end\n\n        @final = true\n      end\n\n      if init_hash.include?(KEY_VALUE)\n        if @kind == ATTRIBUTE_KIND_DERIVED || @kind == ATTRIBUTE_KIND_GIVEN_OR_DERIVED\n          raise Puppet::ParseError, _(\"%{label} of kind '%{kind}' cannot be combined with an attribute value\") % { label: label, kind: @kind }\n        end\n\n        v = init_hash[KEY_VALUE]\n        @value = v == :default ? v : TypeAsserter.assert_instance_of(nil, type, v) { \"#{label} #{KEY_VALUE}\" }\n      else\n        raise Puppet::ParseError, _(\"%{label} of kind 'constant' requires a value\") % { label: label } if @kind == ATTRIBUTE_KIND_CONSTANT\n\n        @value = :undef # Not to be confused with nil or :default\n      end\n    end","sourceCodeStart":288,"sourceCodeEnd":324,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/pops/types/p_object_type.rb#L288-L324","documentation":"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.","triggerScenarios":"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}}}].","commonSituations":"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.","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."],"exampleFix":"# before\n{'type' => Float, 'kind' => 'constant', 'value' => 3.14, 'final' => false}\n\n# after\n{'type' => Float, 'kind' => 'constant', 'value' => 3.14}","handlingStrategy":"validation","validationCode":"# Ruby — validate an attribute hash before declaration\nif h['kind'] == 'constant' && h.key?('final') && !h['final']\n  fail(\"constant implies final; remove final => false\")\nend","typeGuard":"def consistent_finality?(h)\n  h['kind'] != 'constant' || !h.key?('final') || h['final'] == true\nend","tryCatchPattern":null,"preventionTips":["Don't blanket-merge option defaults into attribute hashes; options are kind-specific.","Keep constants minimal: type + kind + value only."],"tags":["puppet","object-type","attribute-declaration","constant","type-declaration"],"backgroundTag":"conflicting-declaration-options","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}