puppetlabs/puppet · error · Puppet::Error

Missing action

Error message

Missing action

What it means

Raised while parsing a symbolic mode clause: the comma-separated part did not match ^([ugoa]*)([-+=].*)$, so no who-plus-action pair exists. There is a who list (or bare permissions) but no operator to say what to do with them.

Source

Thrown at lib/puppet/util/symbolic_file_mode.rb:79

    original_mode = {
      's' => (to_mode & 0o7000) >> 9,
      'u' => (to_mode & 0o0700) >> 6,
      'g' => (to_mode & 0o0070) >> 3,
      'o' => (to_mode & 0o0007) >> 0,
      # Are there any execute bits set in the original mode?
      'any x?' => (to_mode & 0o0111) != 0
    }
    final_mode = {
      's' => original_mode['s'],
      'u' => original_mode['u'],
      'g' => original_mode['g'],
      'o' => original_mode['o'],
    }

    modification.split(/\s*,\s*/).each do |part|
      _, to, dsl = /^([ugoa]*)([-+=].*)$/.match(part).to_a
      if dsl.nil? then raise Puppet::Error, _('Missing action') end

      to = "a" unless to and to.length > 0

      # We want a snapshot of the mode before we start messing with it to
      # make actions like 'a-g' atomic.  Various parts of the DSL refer to
      # the original mode, the final mode, or the current snapshot of the
      # mode, for added fun.
      snapshot_mode = {}
      final_mode.each { |k, v| snapshot_mode[k] = v }

      to.gsub('a', 'ugo').split('').uniq.each do |who|
        value = snapshot_mode[who]

        action = '!'
        actions = {
          '!' => ->(_, _) { raise Puppet::Error, _('Missing operation (-, =, or +)') },
          '=' => ->(m, v) { m | v },
          '+' => ->(m, v) { m | v },

View on GitHub (pinned to e227c27540)

Solutions

  1. Add the operator: 'u+rw', 'g=r-x', 'o-rwx'.
  2. Remove extra/trailing commas and check that every comma-separated clause has who+operator+permissions.

Example fix

# before
file { '/tmp/x': mode => 'rw' }

# after
file { '/tmp/x': mode => 'u+rw' }
Defensive patterns

Strategy: validation

Validate before calling

mode.split(/\s*,\s*/).each do |clause|
  raise ArgumentError, "clause #{clause.inspect} lacks an operator" unless clause =~ /^([ugoa]*)([-+=].*)$/ 
end
Puppet::Util::SymbolicMode.symbolic_mode_to_int(mode)

Type guard

def valid_symbolic_mode?(m)
  m.is_a?(String) && !m.empty? &&
    m.split(/\s*,\s*/).all? { |c| c =~ /^([ugoa]*)([-+=].*)$/ }
end

Prevention

When it happens

Trigger: symbolic_mode_to_int('rx'), mode => 'u', or any clause like 'ugo', 'rwx', or 'x' with no -, + or =; also fragments left behind by stray commas such as 'u+r,g'.

Common situations: Hand-written modes missing the operator ('rw' instead of 'u+rw'); trailing commas splitting the mode into an empty/bare fragment; concatenating variables into mode strings.

Related errors


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