puppetlabs/puppet · error · CommandlineError

option -- must be specified

Error message

option --%{opt} must be specified

What it means

Options declared with `required: true` are collected before parsing (trollop.rb:323-324) and checked afterwards at trollop.rb:413: any that were not present on the command line raise CommandlineError 'option --x must be specified'. A :default does not exempt a required option — required means the user must type the flag; the default only fills the value when the option is absent in code paths that read the parsed hash directly.

Solutions

  1. Supply the missing flag exactly as named in the message
  2. Check --help for required options before running
  3. If the option should be optional, remove `required: true` and give it a :default
  4. For conditional requirements, validate in code after parsing and emit a targeted message

Example fix

# before
opt :env, 'Target environment', type: :string, required: true
$ mytool deploy
Error: option --env must be specified

# after
$ mytool deploy --env production
# or make it optional:
opt :env, 'Target environment', type: :string, default: 'production'
Defensive patterns

Strategy: try-catch

Validate before calling

# Verify every required option is present before parse
specs = parser.instance_variable_get(:@specs)
required = specs.select { |_, o| o[:required] }.keys
given = argv.map { |t| t[/^--no-?(.+)/, 1]&.tr('-', '_')&.to_sym }.compact
missing = required - given
abort "Missing required option(s): --#{missing.map { |s| s.to_s.tr('_', '-') }.join(' --')}" unless missing.empty?

Try / catch

begin
  opts = parser.parse(argv)
rescue Puppet::Util::CommandLine::Trollop::CommandlineError => e
  raise unless e.message.include?('must be specified')
  # optionality fallback: re-parse with a default injected instead of required
  specs = parser.instance_variable_get(:@specs)
  opt_name = e.message[/option --(.+) must be specified/, 1].tr('-', '_').to_sym
  specs[opt_name][:required] = false
  specs[opt_name][:default] ||= fallback_value_for(opt_name)
  opts = parser.parse(argv)
end

Prevention

When it happens

Trigger: Running a face or subcommand while omitting its required option; a cron job or systemd unit invoking the tool with an incomplete ARGV.

Common situations: First runs without reading --help; environment-specific wrappers dropping arguments; upgrading a tool where a formerly optional flag became required.

Understand the failure class

Background: "Must pass :limit option" / "Missing required option" — required option errors explained — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at lib/puppet/util/command_line/trollop.rb:413

        raise VersionNeeded if given_args.include? :version
        raise HelpNeeded if given_args.include? :help
      end

      ## check constraint satisfaction
      @constraints.each do |type, syms|
        constraint_sym = syms.find { |sym| given_args[sym] }
        next unless constraint_sym

        case type
        when :depends
          syms.each { |sym| raise CommandlineError, _("--%{value0} requires --%{value1}") % { value0: @specs[constraint_sym][:long], value1: @specs[sym][:long] } unless given_args.include? sym }
        when :conflicts
          syms.each { |sym| raise CommandlineError, _("--%{value0} conflicts with --%{value1}") % { value0: @specs[constraint_sym][:long], value1: @specs[sym][:long] } if given_args.include?(sym) && (sym != constraint_sym) }
        end
      end

      required.each do |sym, _val|
        raise CommandlineError, _("option --%{opt} must be specified") % { opt: @specs[sym][:long] } unless given_args.include? sym
      end

      ## parse parameters
      given_args.each do |sym, given_data|
        arg = given_data[:arg]
        params = given_data[:params]

        opts = @specs[sym]
        raise CommandlineError, _("option '%{arg}' needs a parameter") % { arg: arg } if params.empty? && opts[:type] != :flag

        vals["#{sym}_given".intern] = true # mark argument as specified on the commandline

        case opts[:type]
        when :flag
          if arg =~ /^--no-/ and sym.to_s =~ /^--\[no-\]/
            vals[sym] = opts[:default]
          else
            vals[sym] = !opts[:default]

View on GitHub (pinned to e227c27540)