puppetlabs/puppet · error · Puppet::Module::Task::InvalidTask

puppet.tasks/multiple-implementations

puppet.tasks/multiple-implementations

Error message

Multiple executables were found in directory %{directory} for task %{name}; define 'implementations' in metadata to differentiate between them

What it means

Raised as Puppet::Error by Config#parse_directive when the `url` value from device.conf fails URI.parse with URI::InvalidURIError. Only strict URI syntax errors trigger it — the scheme, host, or escaping is malformed enough that Ruby's URI parser rejects the string. %{value} echoes the exact text after the `url` keyword.

Source

Thrown at lib/puppet/module/task.rb:192

            msg = _("Task metadata for task %{name} specifies missing implementation %{implementation}" % { name: name, implementation: impl['name'] })
            raise InvalidTask.new(msg, 'puppet.tasks/missing-implementation', { missing: [impl['name']] })
          end
          { "name" => impl['name'], "path" => path }
        end
        return implementations
      end

      # If implementations isn't defined, then we use executables matching the
      # task name, and only one may exist.
      implementations = executables.select { |impl| File.basename(impl, '.*') == basename }
      if implementations.empty?
        msg = _('No source besides task metadata was found in directory %{directory} for task %{name}') %
              { name: name, directory: directory }
        raise InvalidTask.new(msg, 'puppet.tasks/no-implementation')
      elsif implementations.length > 1
        msg = _("Multiple executables were found in directory %{directory} for task %{name}; define 'implementations' in metadata to differentiate between them") %
              { name: name, directory: implementations[0] }
        raise InvalidTask.new(msg, 'puppet.tasks/multiple-implementations')
      end

      [{ "name" => File.basename(implementations.first), "path" => implementations.first }]
    end
    private_class_method :find_implementations

    def self.find_files(name, directory, metadata, executables, envname = nil)
      # PXP agent relies on 'impls' (which is the task file) being first if there is no metadata
      find_implementations(name, directory, metadata, executables) + find_extra_files(metadata, envname)
    end

    def self.is_tasks_metadata_filename?(name)
      is_tasks_filename?(name) && name.end_with?('.json')
    end

    def self.is_tasks_executable_filename?(name)
      is_tasks_filename?(name) && !name.end_with?('.json')
    end

View on GitHub (pinned to e227c27540)

Solutions

  1. Rewrite the url in full form with scheme and encoded credentials: `url https://user:%40pass@device.example.com:443`
  2. URI-encode any reserved characters in the password/host portion (RFC 3986 percent-encoding)
  3. Ensure the scheme matches the device type's expected transport (ssh/telnet/https per the type's documentation)

Example fix

# before
[sw01.example.com]
type cisco
url ssh://admin:p@ss word@sw01.example.com

# after
[sw01.example.com]
type cisco
url ssh://admin:p%40ss%20word@sw01.example.com
Defensive patterns

Strategy: validation

Validate before calling

require 'uri'
url = 'ssh://admin:p%40ss@sw01.example.com'
URI.parse(url) # raises URI::InvalidURIError here instead of inside Puppet
puts 'url ok'

Try / catch

begin
  config.read
rescue Puppet::Error => e
  raise unless e.message =~ /is an invalid url/
  # re-check the url line yourself: URI.parse(value) to get precise offset
  raise
end

Prevention

When it happens

Trigger: A device url with spaces or unescaped special characters, a missing scheme (`sw01` instead of `ssh://sw01`), an unencoded password containing characters like `@` or `#`, or stray quotes/semicolons after the value. The regex captures everything after `url `, so trailing junk ends up inside %{value}.

Common situations: Passwords with reserved characters pasted into the url line; copying telnet/ssh URLs from documentation that wrap or add markup; missing scheme after template refactor.

Related errors


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