puppetlabs/puppet · error · ArgumentError

Cannot alias %{resource} to %{key} at %{resource_declaration

Error message

Cannot alias %{resource} to %{key} at %{resource_declaration}; resource %{newref} already declared

What it means

Raised by Puppet::Resource::Catalog#alias (lib/puppet/resource/catalog.rb:215) when a computed resource reference (Type[key], built from the resource class plus the alias key or namevar) is already present in the catalog's resource table and points to a different resource object. Aliases are normally created implicitly from a resource's namevar (e.g. a file's path) or explicitly via the `alias` metaparameter, so this is Puppet's duplicate-declaration guard. The message reports the declaration site of both the offending and the pre-existing resource.

Source

Thrown at lib/puppet/resource/catalog.rb:215

    # because sometimes an alias is created before the resource is
    # added to the catalog, so comparing inside the below if block
    # isn't sufficient.
    existing = @resource_table[newref]
    if existing
      return if existing == resource

      resource_declaration = Puppet::Util::Errors.error_location(resource.file, resource.line)
      msg = if resource_declaration.empty?
              # TRANSLATORS 'alias' should not be translated
              _("Cannot alias %{resource} to %{key}; resource %{newref} already declared") %
                { resource: ref, key: key.inspect, newref: newref.inspect }
            else
              # TRANSLATORS 'alias' should not be translated
              _("Cannot alias %{resource} to %{key} at %{resource_declaration}; resource %{newref} already declared") %
                { resource: ref, key: key.inspect, resource_declaration: resource_declaration, newref: newref.inspect }
            end
      msg += Puppet::Util::Errors.error_location_with_space(existing.file, existing.line)
      raise ArgumentError, msg
    end
    @resource_table[newref] = resource
    @aliases[ref] ||= []
    @aliases[ref] << newref
  end

  # Apply our catalog to the local host.
  # @param options [Hash{Symbol => Object}] a hash of options
  # @option options [Puppet::Transaction::Report] :report
  #   The report object to log this transaction to. This is optional,
  #   and the resulting transaction will create a report if not
  #   supplied.
  #
  # @return [Puppet::Transaction] the transaction created for this
  #   application
  #
  # @api public
  def apply(options = {})

View on GitHub (pinned to e227c27540)

Solutions

  1. Read the message: it names both declarations via Puppet::Util::Errors.error_location — open each file:line and decide which declaration should win.
  2. If both declarations are meant to be the same resource, delete one or replace it with stdlib's ensure_resource()/ensure_packages() so the second declaration is a no-op.
  3. If titles must differ, give the resource its canonical namevar as title (e.g. file {'/etc/app.conf': ...}) and remove conflicting `alias` metaparameters.
  4. If two distinct resources are intended, change the title or namevar so they no longer produce the same Type[key] reference (different path, different defined-type title).

Example fix

# before
file { '/etc/nginx/nginx.conf':
  ensure => present,
}
file { 'nginx-main-conf':
  path   => '/etc/nginx/nginx.conf',  # namevar alias collides with File[/etc/nginx/nginx.conf]
  ensure => present,
}

# after
file { '/etc/nginx/nginx.conf':
  ensure => present,
}
# or make the second declaration idempotent:
# ensure_resource('file', '/etc/nginx/nginx.conf', { 'ensure' => 'present' })
Defensive patterns

Strategy: validation

Validate before calling

# before adding or aliasing a resource, confirm the reference is free
ref_string = "#{resource.type}[#{key}]"
existing = catalog.resource(ref_string)
if existing && existing != resource
  raise ArgumentError, "#{ref_string} already declared at #{existing.file}:#{existing.line}"
end
catalog.alias(resource, key)

Try / catch

begin
  catalog.alias(resource, key)
rescue ArgumentError => e
  raise unless e.message.include?('already declared')
  Puppet.warning("skipping duplicate #{resource.ref}: #{e.message}")
end

Prevention

When it happens

Trigger: Declaring two resources of the same type whose title or namevar resolve to the same reference, e.g. file {'/etc/app.conf': ...} plus file {'app-conf': path => '/etc/app.conf'}; using the `alias` metaparameter with a key equal to another resource's title; calling catalog.alias(resource, key) or catalog.add_resource when @resource_table[[type, key]] already holds a different resource (the method returns silently only when existing == resource or when ref_string == ref).

Common situations: Two modules in the same role/profile both manage the same file, user, or package with different titles; a refactor renames a title while another declaration still uses the old name as an alias; overlapping profiles included on one node; a resource whose namevar (path, command, name) accidentally equals another resource's title.

Related errors


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