{"record":{"id":"2df94bb7a2d48572","repo":"puppetlabs/puppet","slug":"trollop-die-can-only-be-called-after-trollop-opt","errorCode":null,"errorMessage":"Trollop::die can only be called after Trollop::options","messagePattern":"Trollop::die can only be called after Trollop::options","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/puppet/util/command_line/trollop.rb","lineNumber":839,"sourceCode":"  ##   end\n  ##\n  ##   die :volume, \"too loud\" if opts[:volume] > 10.0\n  ##   die :volume, \"too soft\" if opts[:volume] < 0.1\n  ##\n  ## In the one-argument case, simply print that message, a notice\n  ## about -h, and die. Example:\n  ##\n  ##   options do\n  ##     opt :whatever # ...\n  ##   end\n  ##\n  ##   Trollop::die \"need at least one filename\" if ARGV.empty?\n  def die arg, msg = nil\n    if @last_parser\n      @last_parser.die arg, msg\n    else\n      # TRANSLATORS 'Trollop' is the name of a module and 'die' and 'options' are methods in it and should not be translated.\n      raise ArgumentError, _(\"Trollop::die can only be called after Trollop::options\")\n    end\n  end\n\n  module_function :options, :die, :with_standard_exception_handling\n  end # module\nend\nend\nend\n","sourceCodeStart":821,"sourceCodeEnd":848,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/util/command_line/trollop.rb#L821-L848","documentation":"Trollop::die is the module-level helper that reports a fatal usage error, but it only works after Trollop::options has created a parser: die delegates to the @last_parser registered by the most recent options block. If die is called before any options block has run, @last_parser is nil and ArgumentError is raised instead of the intended error message. The problem is purely the order of calls in the embedding application.","triggerScenarios":"A bin script or custom Puppet face that calls Trollop::die('need at least one filename') before ever calling Trollop::options { ... }, typically after a refactor hoists early validation above the parser setup, or when the documented example is copied without its options block.","commonSituations":"Refactors that move argument validation above option parsing, copy-pasting the Trollop usage example without the options block, and code paths that conditionally skip Trollop.options but unconditionally call die.","solutions":["Move the Trollop::options { ... } block so it runs before any Trollop::die call","If validation must happen early, parse options first and then die based on the parsed values or ARGV","Wrap the CLI entry point in with_standard_exception_handling so usage problems print help instead of a Ruby backtrace"],"exampleFix":"# before\nTrollop::die 'need at least one filename' if ARGV.empty?\nopts = Trollop.options { opt :verbose, 'Verbose' }\n# => ArgumentError: Trollop::die can only be called after Trollop::options\n\n# after\nopts = Trollop.options { opt :verbose, 'Verbose' }\nTrollop::die 'need at least one filename' if ARGV.empty?","handlingStrategy":"validation","validationCode":"opts = Trollop.options do\n  opt :verbose, 'Run verbosely'\nend\n# Trollop::die is only safe after this call","typeGuard":null,"tryCatchPattern":"begin\n  Trollop::die('need a file') if ARGV.empty?\nrescue ArgumentError => e\n  abort \"CLI bug: #{e.message} (parse options before die)\"\nend","preventionTips":["Always create the parser with Trollop::options before any Trollop::die call","Keep argument validation immediately after option parsing so the order is obvious"],"tags":["cli","trollop","puppet","api-order"],"backgroundTag":"invalid-call-order","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}