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

all %{opts} patterns must match a key starting with module n

Error message

all %{opts} patterns must match a key starting with module name '%{module_name}'

What it means

When lookup_options comes from module data, validate_lookup_options enforces module scoping: keys starting with '^' (LOOKUP_OPTIONS_PATTERN_START) are regex patterns, and the text right after the caret must equal '<module_name>::' (key[1..pfx.length] == pfx). A module may only define lookup_options patterns matching its own keys; a broader pattern raises Puppet::DataBinding::LookupError.

Source

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

  def set_global_only
    @global_only = true
    self
  end

  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

View on GitHub (pinned to e227c27540)

Solutions

  1. Scope every '^' pattern in module data to your own module: '^mymodule::.*'.
  2. Put cross-module or catch-all patterns in environment-level data instead, where module scoping does not apply.
  3. Remember plain (non-pattern) keys are checked separately — they must also start with 'mymodule::'.

Example fix

# before: modules/mymodule/data/common.yaml
lookup_options:
  '^.*':
    merge: deep

# after
lookup_options:
  '^mymodule::.*':
    merge: deep
Defensive patterns

Strategy: validation

Validate before calling

# CI check: '^' patterns in module data must match the module's own namespace
require 'yaml'

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

Prevention

When it happens

Trigger: In a module's own data (e.g. modules/mymodule/data/common.yaml): `lookup_options: { '^myothermodule::.*': { ... } }` or a generic `'^.*'` — any pattern whose post-caret text is not 'mymodule::'.

Common situations: Module authors trying to set merge behavior for all keys or for other modules' keys from module data; copying environment-level lookup_options verbatim into a module.

Related errors


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