{"record":{"id":"6ff2072dedcefe6d","repo":"puppetlabs/puppet","slug":"the-code-loaded-from-source-ref-produced-plan-w","errorCode":null,"errorMessage":"The code loaded from %{source_ref} produced plan with the wrong name, expected %{expected}, actual %{actual}","messagePattern":"The code loaded from %(.+?) produced plan with the wrong name, expected %(.+?), actual %(.+?)","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/puppet/pops/loader/puppet_plan_instantiator.rb","lineNumber":51,"sourceCode":"    # Only one plan is allowed (and no other definitions)\n    case definitions.size\n    when 0\n      raise ArgumentError, _(\"The code loaded from %{source_ref} does not define the plan '%{plan_name}' - it is empty.\") % { source_ref: source_ref, plan_name: typed_name.name }\n    when 1\n      # ok\n    else\n      raise ArgumentError, _(\"The code loaded from %{source_ref} must contain only the plan '%{plan_name}' - it has additional definitions.\") % { source_ref: source_ref, plan_name: typed_name.name }\n    end\n    the_plan_definition = definitions[0]\n\n    unless the_plan_definition.is_a?(Model::PlanDefinition)\n      raise ArgumentError, _(\"The code loaded from %{source_ref} does not define the plan '%{plan_name}' - no plan found.\") % { source_ref: source_ref, plan_name: typed_name.name }\n    end\n\n    unless the_plan_definition.name == typed_name.name\n      expected = typed_name.name\n      actual = the_plan_definition.name\n      raise ArgumentError, _(\"The code loaded from %{source_ref} produced plan with the wrong name, expected %{expected}, actual %{actual}\") % { source_ref: source_ref, expected: expected, actual: actual }\n    end\n    unless result.body == the_plan_definition\n      raise ArgumentError, _(\"The code loaded from %{source} contains additional logic - can only contain the plan %{plan_name}\") % { source: source_ref, plan_name: typed_name.name }\n    end\n\n    # Adapt the function definition with loader - this is used from logic contained in it body to find the\n    # loader to use when making calls to the new function API. Such logic have a hard time finding the closure (where\n    # the loader is known - hence this mechanism\n    private_loader = loader.private_loader\n    Adapters::LoaderAdapter.adapt(the_plan_definition).loader_name = private_loader.loader_name\n\n    # Cannot bind loaded functions to global scope, that must be done without binding that scope as\n    # loaders survive a compilation.\n    closure_scope = nil\n\n    created = create_function_class(the_plan_definition)\n    # create the function instance - it needs closure (scope), and loader (i.e. where it should start searching for things\n    # when calling functions etc.","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/pops/loader/puppet_plan_instantiator.rb#L33-L69","documentation":"Raised by PuppetPlanInstantiator when the plan file's sole definition is a plan, but its declared name differs from the typed name the loader is binding (derived from the module name plus the file path). A plan named mymod::deploy must live in modules/mymod/plans/deploy.pp; subdirectories add name segments (plans/sub/foo.pp expects mymod::sub::foo).","triggerScenarios":"`the_plan_definition.name != typed_name.name`: e.g. plans/deploy.pp contains `plan mymod::deploy_prod(...)` while the loader resolves typed name mymod::deploy from the path.","commonSituations":"Renaming a plan file but not the plan statement (or vice versa); copy-pasting a plan and editing only one of the two names; adding/removing subdirectory segments without updating the plan's namespace.","solutions":["Make the plan statement name exactly match the module::path-derived name","Rename the file to match the plan name if the plan name is the desired one","Check subdirectory mapping: plans/sub/foo.pp must declare mymod::sub::foo"],"exampleFix":"# before - modules/mymod/plans/deploy.pp\nplan mymod::deploy_prod($n) { run_command('uptime', $n) }\n\n# after\nplan mymod::deploy($n) { run_command('uptime', $n) }","handlingStrategy":"validation","validationCode":"expected = \"#{module_name}::#{File.basename(path, '.pp')}\"\nok = defs[0].is_a?(Puppet::Pops::Model::PlanDefinition) && defs[0].name == expected\nraise ArgumentError, \"plan name #{defs[0].name} != #{expected}\" unless ok","typeGuard":null,"tryCatchPattern":"begin\n  loader.load_typed(typed_name)\nrescue ArgumentError => e\n  raise unless e.message.include?('wrong name')\n  warn \"plan/file name mismatch: #{e.message}\"\nend","preventionTips":["Derive the plan statement name from the file path when creating plans","Rename file and plan statement together in one change","Include subdirectory segments in the plan namespace (plans/sub/x.pp is mod::sub::x)"],"tags":["puppet","bolt","plan","naming","loader"],"backgroundTag":"puppet-definition-name-mismatch","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}