puppetlabs/puppet · error · Puppet::Error

Reference to unresolved type #{@name}

Error message

Reference to unresolved type #{@name}

What it means

A type alias object (PTypeAliasType) is only a name plus an expression until resolve(loader) interprets that expression against a loader. resolved_type returns the interpretation and raises Puppet::Error if resolution has not run yet. Normal manifest code never sees this because TypeParser resolves aliases during parsing; hitting it means the pops API was driven out of order from Ruby, or resolution failed earlier (for example the defining module failed to load).

Source

Thrown at lib/puppet/pops/types/types.rb:3406

    @self_recursion = false
  end

  def assignable?(o, guard = nil)
    if @self_recursion
      guard ||= RecursionGuard.new
      guard.with_this(self) { |state| state == RecursionGuard::SELF_RECURSION_IN_BOTH ? true : super(o, guard) }
    else
      super(o, guard)
    end
  end

  # Returns the resolved type. The type must have been resolved by a call prior to calls to this
  # method or an error will be raised.
  #
  # @return [PAnyType] The resolved type of this alias.
  # @raise [Puppet::Error] unless the type has been resolved prior to calling this method
  def resolved_type
    raise Puppet::Error, "Reference to unresolved type #{@name}" unless @resolved_type

    @resolved_type
  end

  def callable_args?(callable, guard)
    guarded_recursion(guard, false) { |g| resolved_type.callable_args?(callable, g) }
  end

  def check_self_recursion(originator)
    resolved_type.check_self_recursion(originator) unless originator.equal?(self)
  end

  def kind_of_callable?(optional = true, guard = nil)
    guarded_recursion(guard, false) { |g| resolved_type.kind_of_callable?(optional, g) }
  end

  def instance?(o, guard = nil)
    really_instance?(o, guard) == 1

View on GitHub (pinned to e227c27540)

Solutions

  1. Call resolve(loader) on the alias before reading resolved_type.
  2. Make sure the module/TypeSet defining the alias is fully loaded and the name is resolvable from the loader you pass.
  3. Upgrade Puppet - ordering bugs around alias resolution have been fixed over time; a minimal reproducible case should be reported upstream.
  4. In tooling, wrap access in begin/rescue Puppet::Error, resolve, then read again.

Example fix

# before (Ruby)
real = alias_t.resolved_type   # Puppet::Error: Reference to unresolved type

# after
begin
  real = alias_t.resolved_type
rescue Puppet::Error
  alias_t.resolve(loader)
  real = alias_t.resolved_type
end
Defensive patterns

Strategy: try-catch

Validate before calling

# ensure resolution before access (resolve is a no-op once resolved)
alias_t.resolve(loader) if alias_t.instance_variable_get(:@resolved_type).nil?
real = alias_t.resolved_type

Try / catch

begin
  real = alias_t.resolved_type
rescue Puppet::Error
  alias_t.resolve(loader)   # resolution had not run; do it, then read again
  real = alias_t.resolved_type
end

Prevention

When it happens

Trigger: Ruby code holding a PTypeAliasType calls .resolved_type before calling .resolve(loader); an alias is inspected by tooling while the defining TypeSet or module is still loading; an earlier failure (autoload error, missing module) prevented resolve from running.

Common situations: Gems and custom functions that walk the type system manually; type-inspection/debug or documentation tooling; Puppet version changes that reorder alias resolution (a known source of regressions).

Related errors


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