{"record":{"id":"afc72733aca9fe7b","repo":"puppetlabs/puppet","slug":"attempt-to-action-type-name-annotation-decla","errorCode":null,"errorMessage":"attempt to #{action} #{type_name} annotation declared on #{o.label}","messagePattern":"attempt to #(.+?) #(.+?) annotation declared on #(.+?)","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/puppet/pops/types/annotation.rb","lineNumber":55,"sourceCode":"        end\n        adapter = associate_adapter(_pcore_type.from_hash(init_hash), o) unless init_hash.nil?\n      end\n      adapter\n    end\n\n    # Forces the creation or removal of an annotation of this type.\n    # If `init_hash` is a hash, a new annotation is created and returned\n    # If `init_hash` is `nil`, then the annotation is cleared and the previous annotation is returned.\n    #\n    # @param o [Object] object to annotate\n    # @param init_hash [Hash{String,Object},nil] the initializer for the annotation or `nil` to clear the annotation\n    # @return [Annotation<self>] an annotation of the same class as the receiver of the call\n    #\n    def self.annotate_new(o, init_hash)\n      if o.is_a?(Annotatable) && o.annotations.include?(_pcore_type)\n        # Prevent clear or redefine of annotations declared on type\n        action = init_hash == CLEAR ? 'clear' : 'redefine'\n        raise ArgumentError, \"attempt to #{action} #{type_name} annotation declared on #{o.label}\"\n      end\n\n      if init_hash == CLEAR\n        clear(o)\n      else\n        associate_adapter(_pcore_type.from_hash(init_hash), o)\n      end\n    end\n\n    # Uses name of type instead of name of the class (the class is likely dynamically generated and as such,\n    # has no name)\n    # @return [String] the name of the type\n    def self.type_name\n      _pcore_type.name\n    end\n  end\nend\nend","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/pops/types/annotation.rb#L37-L73","documentation":"Annotation.annotate_new(o, init_hash) forces creation or clearing of a Pcore annotation. When o is Annotatable (e.g. a Pcore type declaration or typeset member) and its annotations hash already contains this annotation type, the annotation is considered 'declared on the type' and is immutable at runtime: passing the CLEAR sentinel (the string 'clear') raises 'attempt to clear ...', any other init_hash raises 'attempt to redefine ...'. The message interpolates the annotation type name and o.label (the type/object label).","triggerScenarios":"Calling MyAnnotation.annotate_new(type_declaration, nil) or with a new init hash on an object whose type declaration already carries that annotation; Puppet DSL that mutates annotations on catalog-contained type declarations; code that treats declared annotations like per-instance adapters and tries to overwrite them.","commonSituations":"Module authors implementing rich data (Pcore) types who attempt to clear/redefine annotations during catalog compilation or rich-data round-trips; serialization code that annotates on load and re-annotates on save; confusion between per-object adapters (safe to set/clear) and type-declared annotations (protected).","solutions":["Do not clear or redefine annotations that come from the type declaration - treat them as read-only metadata","For per-instance mutable data, use a distinct annotation type not declared on the Annotatable type, and set it with associate_adapter-based paths (annotate with a block)","Read the existing annotation instead of replacing it: MyAnnotation.annotate(o) returns the declared instance","If you truly need different values, declare a new annotation type name rather than redefining the existing one"],"exampleFix":"// before\nMyAnnotation.annotate_new(o, nil)          # o declares MyAnnotation -> 'attempt to clear'\nMyAnnotation.annotate_new(o, {'x' => 2})   # -> 'attempt to redefine'\n\n// after\nexisting = MyAnnotation.annotate(o)         # read the declared annotation\n# mutable per-instance data goes in a separate, undeclared annotation type:\nRuntimeInfo.annotate_new(o, {'x' => 2})","handlingStrategy":"validation","validationCode":"# only set/clear annotations the type does NOT declare\ndeclared = o.is_a?(Puppet::Pops::Types::Annotatable) && o.annotations.include?(MyAnnotation._pcore_type)\nraise ArgumentError, 'annotation is declared on the type; read-only' if declared\nMyAnnotation.annotate_new(o, init_hash)","typeGuard":"def annotation_mutable?(o, ann_class)\n  !(o.is_a?(Puppet::Pops::Types::Annotatable) && o.annotations.include?(ann_class._pcore_type))\nend","tryCatchPattern":"begin\n  MyAnnotation.annotate_new(o, init_hash)\nrescue ArgumentError => e\n  raise DataError, \"declared annotation is immutable: #{e.message}\" if e.message.start_with?('attempt to')\n  raise\nend","preventionTips":["Treat type-declared annotations as read-only metadata; read them with MyAnnotation.annotate(o)","Keep mutable per-instance state in a separate annotation type that the type does not declare","Never re-annotate during serialization round-trips - reuse the existing adapter"],"tags":["puppet","pcore","annotation","immutability","argument-error"],"backgroundTag":"annotation-redefine-forbidden","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}