{"record":{"id":"b217452f658c33e9","repo":"puppetlabs/puppet","slug":"x-only-works-with-the-operator","errorCode":null,"errorMessage":"X only works with the '+' operator","messagePattern":"X only works with the '\\+' operator","errorType":"validation","errorClass":"Puppet::Error","httpStatus":null,"severity":"error","filePath":"lib/puppet/util/symbolic_file_mode.rb","lineNumber":117,"sourceCode":"        }\n\n        dsl.split('').each do |op|\n          case op\n          when /[-+=]/\n            action = op\n            # Clear all bits, if this is assignment\n            value  = 0 if op == '='\n\n          when /[ugo]/\n            value = actions[action].call(value, snapshot_mode[op])\n\n          when /[rwx]/\n            value = actions[action].call(value, SymbolicMode[op])\n\n          when 'X'\n            # Only meaningful in combination with \"set\" actions.\n            if action != '+'\n              raise Puppet::Error, _(\"X only works with the '+' operator\")\n            end\n\n            # As per the BSD manual page, set if this is a directory, or if\n            # any execute bit is set on the original (unmodified) mode.\n            # Ignored otherwise; it is \"add if\", not \"add or clear\".\n            if is_a_directory or original_mode['any x?']\n              value = actions[action].call(value, ExecBit)\n            end\n\n          when /[st]/\n            bit = SymbolicSpecialToBit[op][who] or fail _(\"internal error\")\n            final_mode['s'] = actions[action].call(final_mode['s'], bit)\n\n          else\n            raise Puppet::Error, _('Unknown operation')\n          end\n        end\n","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/util/symbolic_file_mode.rb#L99-L135","documentation":"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.","triggerScenarios":"mode => 'a-X' or 'u=X' — any symbolic clause where X appears after '-' or '=' instead of '+'.","commonSituations":"Porting shell cleanup scripts (chmod a-X) to Puppet manifests; automated mode rewriting that swaps x for X indiscriminately.","solutions":["Use lowercase x with - and = clauses ('a-x', 'u=x').","Keep X only inside + clauses ('a+X')."],"exampleFix":"# before\nfile { '/opt/app': mode => 'a-X' }\n\n# after\nfile { '/opt/app': mode => 'a-x' }","handlingStrategy":"validation","validationCode":"mode.split(/\\s*,\\s*/).each do |c|\n  op = c[/^([ugoa]*)([-+=])/, 2]\n  raise ArgumentError, 'X requires +' if c.include?('X') && op && op != '+'\nend\nPuppet::Util::SymbolicMode.symbolic_mode_to_int(mode)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Remember X means add-if-executable and pairs only with '+'.","Use lowercase x for '-' and '=' clauses."],"tags":["puppet","file-mode","symbolic-mode","permissions","x-bit"],"backgroundTag":"invalid-symbolic-mode","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}