puppetlabs/puppet · error · ArgumentError

%{option} already has a default value

Error message

%{option} already has a default value

What it means

OptionBuilder#default_to raises when `@option.has_default?` is already true — an option can carry only one default (lib/puppet/interface/option_builder.rb:101). Puppet does not chain or override defaults, so the second declaration is a definition error, not a replacement.

Source

Thrown at lib/puppet/interface/option_builder.rb:101

  # defaults to setting it as a required option.
  # @api public
  # @dsl Faces
  def required(value = true)
    @option.required = value
  end

  # Sets a block that will be used to compute the default value for this
  # option. It will be evaluated when the action is invoked. The block
  # should take no arguments.
  # @api public
  # @dsl Faces
  def default_to(&block)
    unless block
      # TRANSLATORS 'default_to' is a method name and should not be translated
      raise ArgumentError, _("%{option} default_to requires a block") % { option: @option }
    end
    if @option.has_default?
      raise ArgumentError, _("%{option} already has a default value") % { option: @option }
    end
    unless block.arity == 0
      # TRANSLATORS 'default_to' is a method name and should not be translated
      raise ArgumentError, _("%{option} default_to block should not take any arguments") % { option: @option }
    end

    @option.default = block
  end
end

View on GitHub (pinned to e227c27540)

Solutions

  1. Keep a single `default_to` block and put the branching inside it: `default_to { env == :test ? 'dev' : 'production' }`
  2. Delete the stale default after consolidating
  3. Remember `required` + `default_to` is also rejected (see errors 280/282) — pick exactly one of required/default per option

Example fix

# before
option "--environment" do
  default_to { "production" }
  default_to { "development" }
end

# after
option "--environment" do
  default_to { Puppet.settings[:environment] }
end
Defensive patterns

Strategy: validation

Validate before calling

# on an Option object before setting a default
raise ArgumentError, 'default already set' if opt.has_default?
opt.default = -> { 'production' }

Prevention

When it happens

Trigger: Two `default_to` blocks in one option block; a `default_to` call after the Option already got a default via `opt.default = proc`.

Common situations: Copy-pasted option blocks both carrying defaults; environment-specific tuning that appends a second default instead of editing the first.

Related errors


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