{"record":{"id":"75fdb6bdaadb59e8","repo":"puppetlabs/puppet","slug":"all-opts-keys-must-start-with-module-name-mo","errorCode":null,"errorMessage":"all %{opts} keys must start with module name '%{module_name}'","messagePattern":"all %(.+?) keys must start with module name '%(.+?)'","errorType":"exception","errorClass":"Puppet::DataBinding::LookupError","httpStatus":null,"severity":"error","filePath":"lib/puppet/pops/lookup/lookup_adapter.rb","lineNumber":311,"sourceCode":"\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\n        key_options[key] = value\n      end\n    end\n    [key_options.empty? ? nil : key_options, pattern_options.empty? ? nil : pattern_options]","sourceCodeStart":293,"sourceCodeEnd":329,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/pops/lookup/lookup_adapter.rb#L293-L329","documentation":"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.","triggerScenarios":"modules/mymodule/data/common.yaml with `lookup_options: { 'myothermodule::key': {...} }` or an unnamespaced `lookup_options: { 'mykey': {...} }` — neither starts with 'mymodule::'.","commonSituations":"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.","solutions":["Prefix every plain lookup_options key in module data with your module name: 'mymodule::key'.","Move options for keys outside your module to environment-level data.","If the key is a regex intent, use '^mymodule::...' pattern syntax instead (subject to the pattern rule)."],"exampleFix":"# before: modules/mymodule/data/common.yaml\nlookup_options:\n  mykey:\n    convert_to: 'Integer'\n\n# after\nlookup_options:\n  mymodule::mykey:\n    convert_to: 'Integer'","handlingStrategy":"validation","validationCode":"# CI check: plain lookup_options keys in module data must be module-namespaced\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 if key.start_with?('^')\n    abort \"#{f}: key '#{key}' must start with '#{mod}::'\" unless key.start_with?(\"#{mod}::\")\n  end\nend","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Spell out the full namespace ('mymodule::key') in every module-data lookup_options entry.","Options for keys owned by other modules belong in the environment's data, not the module's.","Add the namespace check to the same CI lint pass as the pattern check."],"tags":["puppet","hiera","lookup-options","module-scoping","namespace"],"backgroundTag":"hiera-lookup-options-key-module-scope","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}