{"record":{"id":"e69d1766161972d7","repo":"puppetlabs/puppet","slug":"all-opts-patterns-must-match-a-key-starting-wit","errorCode":null,"errorMessage":"all %{opts} patterns must match a key starting with module name '%{module_name}'","messagePattern":"all %(.+?) patterns must match a key starting with module name '%(.+?)'","errorType":"exception","errorClass":"Puppet::DataBinding::LookupError","httpStatus":null,"severity":"error","filePath":"lib/puppet/pops/lookup/lookup_adapter.rb","lineNumber":307,"sourceCode":"  def set_global_only\n    @global_only = true\n    self\n  end\n\n  private\n\n  PROVIDER_STACK = [:lookup_global, :lookup_in_environment, :lookup_in_module].freeze\n\n  def validate_lookup_options(options, module_name)\n    return nil if options.nil?\n    raise Puppet::DataBinding::LookupError, _(\"value of %{opts} must be a hash\") % { opts: LOOKUP_OPTIONS } unless options.is_a?(Hash)\n    return options if module_name.nil?\n\n    pfx = \"#{module_name}::\"\n    options.each_pair do |key, _value|\n      if key.start_with?(LOOKUP_OPTIONS_PATTERN_START)\n        unless key[1..pfx.length] == pfx\n          raise Puppet::DataBinding::LookupError, _(\"all %{opts} patterns must match a key starting with module name '%{module_name}'\") % { opts: LOOKUP_OPTIONS, module_name: module_name }\n        end\n      else\n        unless key.start_with?(pfx)\n          raise Puppet::DataBinding::LookupError, _(\"all %{opts} keys must start with module name '%{module_name}'\") % { opts: LOOKUP_OPTIONS, module_name: module_name }\n        end\n      end\n    end\n  end\n\n  def compile_patterns(options)\n    return nil if options.nil?\n\n    key_options = {}\n    pattern_options = {}\n    options.each_pair do |key, value|\n      if key.start_with?(LOOKUP_OPTIONS_PATTERN_START)\n        pattern_options[Regexp.compile(key)] = value\n      else","sourceCodeStart":289,"sourceCodeEnd":325,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/pops/lookup/lookup_adapter.rb#L289-L325","documentation":"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.","triggerScenarios":"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::'.","commonSituations":"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.","solutions":["Scope every '^' pattern in module data to your own module: '^mymodule::.*'.","Put cross-module or catch-all patterns in environment-level data instead, where module scoping does not apply.","Remember plain (non-pattern) keys are checked separately — they must also start with 'mymodule::'."],"exampleFix":"# before: modules/mymodule/data/common.yaml\nlookup_options:\n  '^.*':\n    merge: deep\n\n# after\nlookup_options:\n  '^mymodule::.*':\n    merge: deep","handlingStrategy":"validation","validationCode":"# CI check: '^' patterns in module data must match the module's own namespace\nrequire 'yaml'\n\nDir['modules/*/data/**/*.yaml'].each do |f|\n  mod = f.split('/')[1]\n  (YAML.load_file(f)['lookup_options'] || {}).each_key do |key|\n    next unless key.start_with?('^')\n    abort \"#{f}: pattern '#{key}' must start with '^#{mod}::'\" unless key[1..(\"#{mod}::\".length)] == \"#{mod}::\"\n  end\nend","typeGuard":null,"tryCatchPattern":null,"preventionTips":["In module data, always write patterns as '^<modulename>::...'.","Reserve catch-all ('^.*') and cross-module patterns for environment-level data.","Test module data loading with `puppet lookup --module <name>` style checks in CI."],"tags":["puppet","hiera","lookup-options","module-scoping","regex-pattern"],"backgroundTag":"hiera-lookup-options-pattern-module-scope","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}