puppetlabs/puppet · error · Puppet::DataBinding::LookupError

all %{opts} keys must start with module name '%{module_name}

Error message

all %{opts} keys must start with module name '%{module_name}'

What it means

The plain-key counterpart of the pattern rule: inside module-sourced lookup_options, every key that does not start with '^' must literally start with '<module_name>::' (key.start_with?(pfx)), otherwise Puppet::DataBinding::LookupError is raised. A module's data can only configure lookup options for its own namespaced keys, preventing one module from shadowing options of others.

Source

Thrown at lib/puppet/pops/lookup/lookup_adapter.rb:311

  private

  PROVIDER_STACK = [:lookup_global, :lookup_in_environment, :lookup_in_module].freeze

  def validate_lookup_options(options, module_name)
    return nil if options.nil?
    raise Puppet::DataBinding::LookupError, _("value of %{opts} must be a hash") % { opts: LOOKUP_OPTIONS } unless options.is_a?(Hash)
    return options if module_name.nil?

    pfx = "#{module_name}::"
    options.each_pair do |key, _value|
      if key.start_with?(LOOKUP_OPTIONS_PATTERN_START)
        unless key[1..pfx.length] == pfx
          raise Puppet::DataBinding::LookupError, _("all %{opts} patterns must match a key starting with module name '%{module_name}'") % { opts: LOOKUP_OPTIONS, module_name: module_name }
        end
      else
        unless key.start_with?(pfx)
          raise Puppet::DataBinding::LookupError, _("all %{opts} keys must start with module name '%{module_name}'") % { opts: LOOKUP_OPTIONS, module_name: module_name }
        end
      end
    end
  end

  def compile_patterns(options)
    return nil if options.nil?

    key_options = {}
    pattern_options = {}
    options.each_pair do |key, value|
      if key.start_with?(LOOKUP_OPTIONS_PATTERN_START)
        pattern_options[Regexp.compile(key)] = value
      else
        key_options[key] = value
      end
    end
    [key_options.empty? ? nil : key_options, pattern_options.empty? ? nil : pattern_options]

View on GitHub (pinned to e227c27540)

Solutions

  1. Prefix every plain lookup_options key in module data with your module name: 'mymodule::key'.
  2. Move options for keys outside your module to environment-level data.
  3. If the key is a regex intent, use '^mymodule::...' pattern syntax instead (subject to the pattern rule).

Example fix

# before: modules/mymodule/data/common.yaml
lookup_options:
  mykey:
    convert_to: 'Integer'

# after
lookup_options:
  mymodule::mykey:
    convert_to: 'Integer'
Defensive patterns

Strategy: validation

Validate before calling

# CI check: plain lookup_options keys in module data must be module-namespaced
require 'yaml'

Dir['modules/*/data/**/*.yaml'].each do |f|
  mod = f.split('/')[1]
  (YAML.load_file(f)['lookup_options'] || {}).each_key do |key|
    next if key.start_with?('^')
    abort "#{f}: key '#{key}' must start with '#{mod}::'" unless key.start_with?("#{mod}::")
  end
end

Prevention

When it happens

Trigger: modules/mymodule/data/common.yaml with `lookup_options: { 'myothermodule::key': {...} }` or an unnamespaced `lookup_options: { 'mykey': {...} }` — neither starts with 'mymodule::'.

Common situations: Module data written before namespacing rules were understood; environment data copied into a module; keys missing the module prefix because the author assumed module context is implicit.

Related errors


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