puppetlabs/puppet · error · ArgumentError

Cannot use undef as a class name

Error message

Cannot use undef as a class name

What it means

Raised by Scope#transform_and_assert_classnames when an element of the names array is nil (NilClass branch). This method normalizes arguments to include/contain/require-style class references; a nil element means the caller asked to include 'undef', which has no meaningful class target. Note it raises ArgumentError rather than Puppet::ParseError, so it surfaces as a plain evaluation error.

Source

Thrown at lib/puppet/parser/scope.rb:1084

  # Transforms references to classes to the form suitable for
  # lookup in the compiler.
  #
  # Makes names passed in the names array absolute if they are relative.
  #
  # Transforms Class[] and Resource[] type references to class name
  # or raises an error if a Class[] is unspecific, if a Resource is not
  # a 'class' resource, or if unspecific (no title).
  #
  #
  # @param names [Array<String>] names to (optionally) make absolute
  # @return [Array<String>] names after transformation
  #
  def transform_and_assert_classnames(names)
    names.map do |name|
      case name
      when NilClass
        raise ArgumentError, _("Cannot use undef as a class name")
      when String
        raise ArgumentError, _("Cannot use empty string as a class name") if name.empty?

        name.sub(/^([^:]{1,2})/, '::\1')

      when Puppet::Resource
        assert_class_and_title(name.type, name.title)
        name.title.sub(/^([^:]{1,2})/, '::\1')

      when Puppet::Pops::Types::PClassType
        # TRANSLATORS "Class" and "Type" are Puppet keywords and should not be translated
        raise ArgumentError, _("Cannot use an unspecific Class[] Type") unless name.class_name

        name.class_name.sub(/^([^:]{1,2})/, '::\1')

      when Puppet::Pops::Types::PResourceType
        assert_class_and_title(name.type_name, name.title)
        name.title.sub(/^([^:]{1,2})/, '::\1')

View on GitHub (pinned to e227c27540)

Solutions

  1. Guard the include: `if $maybe { include $maybe }` or `if $maybe != undef { include $maybe }`.
  2. Give the lookup a default: `$maybe = lookup('classes::extra', String, 'first', 'absent')` then conditionally include.
  3. Filter nils out of lists before iterating: `$classes = lookup('classes', Array, 'unique', []).filter |$c| { $c != undef }`.

Example fix

# before
include $optional_class   # $optional_class is undef -> Cannot use undef as a class name

# after
$optional_class = lookup('profile::optional', Optional[String], 'first', undef)
if $optional_class {
  include $optional_class
}
Defensive patterns

Strategy: type-guard

Validate before calling

$name = lookup('opt::class', Optional[String], 'first', undef)
include $name if $name != undef

Type guard

# Puppet DSL narrowing — only include when a real name exists:
if $maybe =~ NonEmptyString {
  include $maybe
}
# Ruby API:
def includable?(name)
  name.is_a?(String) && !name.empty?
end

Prevention

When it happens

Trigger: `include $maybe` where $maybe is undef (variable never set, or set to undef explicitly); `include $var` where Hiera lookup returned nothing; `contain Class[$missing]` with $missing undef; API calls `scope.transform_and_assert_classnames([nil])` or functions like realize() receiving nil.

Common situations: Optional classes driven by Hiera keys that are absent ('include' of a lookup with no default); strict_variables runs turning a previously-silent nil into a visible nil; hiera_array/hiera_hash returning empty and code doing `include $list[0]`.

Related errors


AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21). Data as JSON: /api/errors/9c1be34feb460817. Report an issue: GitHub.