puppetlabs/puppet · warning · Puppet::Module::Task::InvalidMetadata
puppet.tasks/unreadable-metadata
puppet.tasks/unreadable-metadata
Error message
Error reading metadata: %{message} What it means
Raised as Puppet::Error by Config#parse_directive when var is anything other than 'type', 'url', or 'debug'. In practice it is unreachable through Config#read because the preceding line regex only lets type|url|debug lines reach parse_directive; the branch is defensive code against future directives or direct calls. If you see it, something is calling parse_directive directly with an unknown key.
Source
Thrown at lib/puppet/module/task.rb:248
raise InvalidName, _("Task names must start with a lowercase letter and be composed of only lowercase letters, numbers, and underscores")
end
name = task_name == "init" ? pup_module.name : "#{pup_module.name}::#{task_name}"
@module = pup_module
@name = name
@metadata_file = metadata_file
@module_executables = module_executables || []
end
def self.read_metadata(file)
if file
content = Puppet::FileSystem.read(file, :encoding => 'utf-8')
content.empty? ? {} : Puppet::Util::Json.load(content)
end
rescue SystemCallError, IOError => err
msg = _("Error reading metadata: %{message}" % { message: err.message })
raise InvalidMetadata.new(msg, 'puppet.tasks/unreadable-metadata')
rescue Puppet::Util::Json::ParseError => err
raise InvalidMetadata.new(err.message, 'puppet.tasks/unparseable-metadata')
end
def metadata
@metadata ||= self.class.read_metadata(@metadata_file)
end
def files
@files ||= self.class.find_files(@name, @module.tasks_directory, metadata, @module_executables, environment_name)
end
def validate
files
true
end
def ==(other)View on GitHub (pinned to e227c27540)
Solutions
- If calling parse_directive directly, pass only 'type', 'url', or 'debug' as var
- If you extended the reader regex, extend parse_directive's case with your new key in the same patch
- Un-vendor/align Puppet versions so the regex and the case statement come from the same release
Example fix
# before config.parse_directive(device, 'user', 'admin', 4) # raises Invalid argument 'user' # after config.parse_directive(device, 'url', 'ssh://admin@sw01.example.com', 4)
Defensive patterns
Strategy: type-guard
Type guard
SUPPORTED_DIRECTIVES = %w[type url debug].freeze def supported_directive?(var) SUPPORTED_DIRECTIVES.include?(var) end config.parse_directive(device, var, value, line) if supported_directive?(var)
Try / catch
begin
config.parse_directive(device, var, value, line)
rescue Puppet::Error => e
raise unless e.message =~ /Invalid argument/
Puppet.debug("ignoring unsupported device.conf directive #{var}")
end Prevention
- If you patch the device.conf reader regex, patch parse_directive's case in the same change
- Do not call parse_directive with ad-hoc keys; extend both sides atomically
- Avoid vendoring old copies of config.rb alongside a newer Puppet
When it happens
Trigger: Custom code invoking Puppet::Util::NetworkDevice::Config#parse_directive(device, 'user', 'admin', line) or similar with an unsupported var; a patched/older read regex that forwards new directive names to an unpatched parse_directive after a partial upgrade.
Common situations: Monkey-patches or vendored forks that add directives to the regex but not to the case statement; version skew between a patched config reader and the stock parser.
Related errors
- puppet.tasks/missing-implementation
- puppet.tasks/no-implementation
- puppet.tasks/multiple-implementations
- PathPatterns cannot be created with a zero byte.
- Request to Puppet Forge failed. Detail: %{detail}.
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/3aae7c3e252c3cd4.
Report an issue: GitHub.