puppetlabs/puppet · error · ArgumentError

The code loaded from %{source_ref} must contain only the cre

Error message

The code loaded from %{source_ref} must contain only the creation of resource type '%{type_name}' - it has additional logic.

What it means

Raised by PuppetResourceTypeImplInstantiator when the file contains the Resource::ResourceTypeImpl.new call plus anything else. The instantiator requires statements.size == 1 -- the file must be only the creation call, with no additional expressions or definitions.

Source

Thrown at lib/puppet/pops/loader/puppet_resource_type_impl_instantiator.rb:55

    rname = Resource::ResourceTypeImpl._pcore_type.name
    unless statements.find do |s|
      if s.is_a?(Model::CallMethodExpression)
        functor_expr = s.functor_expr
        functor_expr.is_a?(Model::NamedAccessExpression) &&
        functor_expr.left_expr.is_a?(Model::QualifiedReference) &&
        functor_expr.left_expr.cased_value == rname &&
        functor_expr.right_expr.is_a?(Model::QualifiedName) &&
        functor_expr.right_expr.value == 'new'
      else
        false
      end
    end
      raise ArgumentError, _("The code loaded from %{source_ref} does not create the resource type '%{type_name}' - no call to %{rname}.new found.") % { source_ref: source_ref, type_name: typed_name.name, rname: rname }
    end

    unless statements.size == 1
      raise ArgumentError, _("The code loaded from %{source_ref} must contain only the creation of resource type '%{type_name}' - it has additional logic.") % { source_ref: source_ref, type_name: typed_name.name }
    end

    closure_scope = Puppet.lookup(:global_scope) { {} }
    resource_type_impl = parser.evaluate(closure_scope, model)

    unless resource_type_impl.is_a?(Puppet::Pops::Resource::ResourceTypeImpl)
      got = resource_type.class
      raise ArgumentError, _("The code loaded from %{source_ref} does not define the resource type '%{type_name}' - got '%{got}'.") % { source_ref: source_ref, type_name: typed_name.name, got: got }
    end

    unless resource_type_impl.name == typed_name.name
      expected = typed_name.name
      actual = resource_type_impl.name
      raise ArgumentError, _("The code loaded from %{source_ref} produced resource type with the wrong name, expected '%{expected}', actual '%{actual}'") % { source_ref: source_ref, expected: expected, actual: actual }
    end

    # Adapt the resource type definition with loader - this is used from logic contained in it body to find the
    # loader to use when making calls to the new function API. Such logic have a hard time finding the closure (where

View on GitHub (pinned to e227c27540)

Solutions

  1. Reduce the file to exactly one statement: the Resource::ResourceTypeImpl.new(...) call
  2. Move each additional resource type to its own file
  3. Move helper logic into functions or plan code, not the type file

Example fix

# before
notice('defining thing')
Resource::ResourceTypeImpl.new('mymod::thing', attributes: { ... })

# after
Resource::ResourceTypeImpl.new('mymod::thing', attributes: { ... })
Defensive patterns

Strategy: validation

Validate before calling

raise ArgumentError, "expected exactly 1 statement, got #{statements.size}" unless statements.size == 1

Try / catch

begin
  loader.load_typed(typed_name)
rescue ArgumentError => e
  raise unless e.message.include?('additional logic')
  warn "trim resource type file to one statement: #{e.message}"
end

Prevention

When it happens

Trigger: `statements.size != 1` after the constructor-call check passed: e.g. the creation call plus a notice() call, an assignment, or a second creation call in the same file.

Common situations: Adding debug statements or comments-as-code near the call; defining two resource types in one file; leftover scaffolding expressions.

Related errors


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