puppetlabs/puppet · error · Puppet::Error

X only works with the '+' operator

Error message

X only works with the '+' operator

What it means

Raised when the capital-X directive is used with an operator other than '+'. X means 'add execute only for directories or files already executable somewhere' and is only defined for adding; removing or assigning it is ambiguous, so the parser rejects it.

Source

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

        }

        dsl.split('').each do |op|
          case op
          when /[-+=]/
            action = op
            # Clear all bits, if this is assignment
            value  = 0 if op == '='

          when /[ugo]/
            value = actions[action].call(value, snapshot_mode[op])

          when /[rwx]/
            value = actions[action].call(value, SymbolicMode[op])

          when 'X'
            # Only meaningful in combination with "set" actions.
            if action != '+'
              raise Puppet::Error, _("X only works with the '+' operator")
            end

            # As per the BSD manual page, set if this is a directory, or if
            # any execute bit is set on the original (unmodified) mode.
            # Ignored otherwise; it is "add if", not "add or clear".
            if is_a_directory or original_mode['any x?']
              value = actions[action].call(value, ExecBit)
            end

          when /[st]/
            bit = SymbolicSpecialToBit[op][who] or fail _("internal error")
            final_mode['s'] = actions[action].call(final_mode['s'], bit)

          else
            raise Puppet::Error, _('Unknown operation')
          end
        end

View on GitHub (pinned to e227c27540)

Solutions

  1. Use lowercase x with - and = clauses ('a-x', 'u=x').
  2. Keep X only inside + clauses ('a+X').

Example fix

# before
file { '/opt/app': mode => 'a-X' }

# after
file { '/opt/app': mode => 'a-x' }
Defensive patterns

Strategy: validation

Validate before calling

mode.split(/\s*,\s*/).each do |c|
  op = c[/^([ugoa]*)([-+=])/, 2]
  raise ArgumentError, 'X requires +' if c.include?('X') && op && op != '+'
end
Puppet::Util::SymbolicMode.symbolic_mode_to_int(mode)

Prevention

When it happens

Trigger: mode => 'a-X' or 'u=X' — any symbolic clause where X appears after '-' or '=' instead of '+'.

Common situations: Porting shell cleanup scripts (chmod a-X) to Puppet manifests; automated mode rewriting that swaps x for X indiscriminately.

Related errors


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