{"record":{"id":"dae4335e50f70f94","repo":"puppetlabs/puppet","slug":"cannot-use-empty-string-as-a-class-name","errorCode":null,"errorMessage":"Cannot use empty string as a class name","messagePattern":"Cannot use empty string as a class name","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/puppet/parser/scope.rb","lineNumber":1086,"sourceCode":"  # lookup in the compiler.\n  #\n  # Makes names passed in the names array absolute if they are relative.\n  #\n  # Transforms Class[] and Resource[] type references to class name\n  # or raises an error if a Class[] is unspecific, if a Resource is not\n  # a 'class' resource, or if unspecific (no title).\n  #\n  #\n  # @param names [Array<String>] names to (optionally) make absolute\n  # @return [Array<String>] names after transformation\n  #\n  def transform_and_assert_classnames(names)\n    names.map do |name|\n      case name\n      when NilClass\n        raise ArgumentError, _(\"Cannot use undef as a class name\")\n      when String\n        raise ArgumentError, _(\"Cannot use empty string as a class name\") if name.empty?\n\n        name.sub(/^([^:]{1,2})/, '::\\1')\n\n      when Puppet::Resource\n        assert_class_and_title(name.type, name.title)\n        name.title.sub(/^([^:]{1,2})/, '::\\1')\n\n      when Puppet::Pops::Types::PClassType\n        # TRANSLATORS \"Class\" and \"Type\" are Puppet keywords and should not be translated\n        raise ArgumentError, _(\"Cannot use an unspecific Class[] Type\") unless name.class_name\n\n        name.class_name.sub(/^([^:]{1,2})/, '::\\1')\n\n      when Puppet::Pops::Types::PResourceType\n        assert_class_and_title(name.type_name, name.title)\n        name.title.sub(/^([^:]{1,2})/, '::\\1')\n      end.downcase\n    end","sourceCodeStart":1068,"sourceCodeEnd":1104,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/parser/scope.rb#L1068-L1104","documentation":"Raised by Scope#transform_and_assert_classnames in the String branch when the class name argument is '' (empty). An empty string usually means a variable interpolation or lookup produced nothing textual, e.g. building a class name dynamically and one fragment was empty. Like the undef case it is an ArgumentError from class-name normalization.","triggerScenarios":"`include \"${prefix}\"` with $prefix unset-but-not-strict (interpolates to ''); `include \"profile::${role}\"` when $role is '' from Hiera; API calls passing '' to include/contain or transform_and_assert_classnames.","commonSituations":"Role/profile patterns composing class names from node data where a role fact is empty on some nodes; migrations where a variable was renamed and interpolations silently yield empty strings; hiera lookups defaulting to ''.","solutions":["Guard the composed name: `if $role != '' and $role != undef { include \"profile::${role}\" }`.","Fail fast with a clearer error at the source: `assert_type(NonEmptyString, $role)` before composing the name.","Fix the upstream data so the interpolated fragment is always populated (Hiera key, fact)."],"exampleFix":"# before\ninclude \"profile::${server_role}\"   # $server_role == '' -> Cannot use empty string as a class name\n\n# after\nif $server_role =~ NonEmptyString {\n  include \"profile::${server_role}\"\n} else {\n  fail(\"server_role must be set, got '${server_role}'\")\n}","handlingStrategy":"type-guard","validationCode":"$name = \"profile::${role}\"\nfail(\"empty role\") unless $name =~ NonEmptyString","typeGuard":"if \"profile::${role}\" =~ NonEmptyString {\n  include \"profile::${role}\"\n}","tryCatchPattern":null,"preventionTips":["Assert NonEmptyString on fragments used to compose class names.","Give Hiera lookups used in name composition non-empty defaults or fail loudly at the lookup site.","Prefer lookup(..., 'unique') lists of fully-formed class names over string composition."],"tags":["puppet","class-reference","empty-string","interpolation","include"],"backgroundTag":"invalid-class-reference","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}