{"record":{"id":"6bb83c16c8fa725b","repo":"puppetlabs/puppet","slug":"could-not-parse-string","errorCode":null,"errorMessage":"Could not parse '%{string}'","messagePattern":"Could not parse '%(.+?)'","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/puppet/settings/config_file.rb","lineNumber":140,"sourceCode":"\n  def extract_fileinfo(string)\n    result = {}\n    value = string.sub(/\\{\\s*([^}]+)\\s*\\}/) do\n      params = ::Regexp.last_match(1)\n      params.split(/\\s*,\\s*/).each do |str|\n        if str =~ /^\\s*(\\w+)\\s*=\\s*(\\w+)\\s*$/\n          param = ::Regexp.last_match(1).intern\n          value = ::Regexp.last_match(2)\n          result[param] = value\n          unless [:owner, :mode, :group].include?(param)\n            raise ArgumentError, _(\"Invalid file option '%{parameter}'\") % { parameter: param }\n          end\n\n          if param == :mode and value !~ /^\\d+$/\n            raise ArgumentError, _(\"File modes must be numbers\")\n          end\n        else\n          raise ArgumentError, _(\"Could not parse '%{string}'\") % { string: string }\n        end\n      end\n      ''\n    end\n    result[:value] = value.sub(/\\s*$/, '')\n    result\n  end\nend\n","sourceCodeStart":122,"sourceCodeEnd":149,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/settings/config_file.rb#L122-L149","documentation":"Each comma-separated entry inside a {...} file-options block must match /^\\s*(\\w+)\\s*=\\s*(\\w+)\\s*$/ — one word, an equals sign, one word. Anything else (empty value `mode =`, values containing dashes/slashes/dots/plus like group = puppet+shadow, trailing commas producing empty strings, stray text) raises ArgumentError 'Could not parse ...' with the whole original setting string for context.","triggerScenarios":"`logdir = /var/log/puppet { owner = puppet, }` (trailing comma -> empty pair); `{ mode = 750, group = domain\\\\users }` (backslashes not word chars); `{ owner = }` empty value; multi-word junk inside the braces.","commonSituations":"Hand-editing file-option blocks; templating that leaves blank values for optional pairs; AD/domain group names or paths pasted into group/owner options; comment text accidentally left inside braces.","solutions":["Keep every pair strictly as name = value with single-word values (letters, digits, underscore only).","Remove trailing/leading commas and never leave an empty value; drop the pair entirely if unset.","For values with punctuation (domain groups), precompute a plain name Puppet's regex accepts or manage ownership via a file resource instead."],"exampleFix":"# before\nvardir = /opt/puppet { owner = puppet, mode = 750, }\n\n# after\nvardir = /opt/puppet { owner = puppet, mode = 750 }","handlingStrategy":"validation","validationCode":"block.split(/\\s*,\\s*/).each do |pair|\n  raise ArgumentError, \"unparseable file option pair: #{pair.inspect}\" unless pair.match?(/^\\s*(\\w+)\\s*=\\s*(\\w+)\\s*$/)\nend","typeGuard":null,"tryCatchPattern":"begin\n  Puppet::Settings::ConfigFile.parse_file(file, text, [])\nrescue ArgumentError => e\n  raise unless e.message.include?(\"Could not parse\")\n  Puppet.err(\"each {...} entry must be name = value with single-word values: #{e.message}\")\n  raise\nend","preventionTips":["Keep {...} entries strictly word = word; no paths, dashes, pluses, or dots in values","Never leave trailing commas or empty values inside the braces","For names with punctuation (domain groups), manage ownership via a file resource instead"],"tags":["puppet","settings","config-file","parse-error","file-options"],"backgroundTag":"config-parse-error","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}