{"record":{"id":"4a6a8e1340b8c4e2","repo":"puppetlabs/puppet","slug":"cannot-transform-a-number-to-a-tag","errorCode":null,"errorMessage":"Cannot transform a number to a tag","messagePattern":"Cannot transform a number to a tag","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/puppet/pops/evaluator/collector_transformer.rb","lineNumber":107,"sourceCode":"    end\n  end\n\n  def query_ComparisonExpression(o, scope)\n    left_code = query(o.left_expr, scope)\n    right_code = query(o.right_expr, scope)\n\n    case o.operator\n    when '=='\n      if left_code == \"tag\"\n        # Ensure that to_s and downcase is done once, i.e. outside the proc block and\n        # then use raw_tagged? instead of tagged?\n        if right_code.is_a?(Array)\n          tags = right_code\n        else\n          tags = [right_code]\n        end\n        tags = tags.collect do |t|\n          raise ArgumentError, _('Cannot transform a number to a tag') if t.is_a?(Numeric)\n\n          t.to_s.downcase\n        end\n        proc do |resource|\n          resource.raw_tagged?(tags)\n        end\n      else\n        proc do |resource|\n          if (tmp = resource[left_code]).is_a?(Array)\n            @@compare_operator.include?(tmp, right_code, scope)\n          else\n            @@compare_operator.equals(tmp, right_code)\n          end\n        end\n      end\n    when '!='\n      proc do |resource|\n        !@@compare_operator.equals(resource[left_code], right_code)","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/pops/evaluator/collector_transformer.rb#L89-L125","documentation":"Raised inside Puppet::Pops::Evaluator::CollectorTransformer while translating a collection search expression whose operator is '==' with left side 'tag'. Tag comparisons are compiled into a static tag list used by resource.raw_tagged?; a Numeric literal on the right cannot be a tag (tags are strings), so transformation aborts with ArgumentError before any resource is collected.","triggerScenarios":"`<| tag == 5 |>`, `User<| tag == 42 |>`, or `Tag<| tag == 1 |>`-style collector statements with a bare numeric literal. Also generated collectors where the right operand is an Integer value rather than a String/Array.","commonSituations":"Copy-paste from docs where tags were quoted; dynamically built search expressions interpolating numbers without quoting; refactoring resource collections during module upgrades.","solutions":["Quote the tag: `<| tag == '5' |>` — tags are always compared as strings.","When building the right side dynamically, coerce first: `\"${number}\"` or `.to_s`.","If the intent was a numeric attribute comparison, use the attribute name instead of `tag`."],"exampleFix":"# before\nFile<| tag == 42 |>   # Cannot transform a number to a tag\n\n# after\nFile<| tag == '42' |>","handlingStrategy":"type-guard","validationCode":"# Coerce dynamic operands to strings before building collectors:\n$tag_val = \"${port}\"    # not the Integer","typeGuard":"# Conceptually what the transformer requires:\n# right operand of `tag ==` must be String or Array<String>\ntags.all? { |t| t.is_a?(String) }","tryCatchPattern":null,"preventionTips":["Always quote tag literals in collector searches.","Interpolate dynamic values (\"${n}\") to force strings before using them as tags.","Use numeric attribute names, not 'tag', when comparing numbers."],"tags":["puppet","collectors","tags","virtual-resources","dsl"],"backgroundTag":"invalid-tag-comparison","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}