{"record":{"id":"2a8337a0b60c5caa","repo":"puppetlabs/puppet","slug":"mount-is-already-mounted-at-name-at-error","errorCode":null,"errorMessage":"%{mount} is already mounted at %{name} at %{error_location}","messagePattern":"%(.+?) is already mounted at %(.+?) at %(.+?)","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/puppet/file_serving/configuration/parser.rb","lineNumber":76,"sourceCode":"\n    @mounts\n  end\n\n  def initialize(filename)\n    @file = Puppet::Util::WatchedFile.new(filename)\n  end\n\n  def changed?\n    @file.changed?\n  end\n\n  private\n\n  # Create a new mount.\n  def newmount(name)\n    if @mounts.include?(name)\n      error_location_str = Puppet::Util::Errors.error_location(@file, @count)\n      raise ArgumentError, _(\"%{mount} is already mounted at %{name} at %{error_location}\") %\n                           { mount: @mounts[name], name: name, error_location: error_location_str }\n    end\n    case name\n    when \"modules\"\n      mount = Mount::Modules.new(name)\n    when \"plugins\"\n      mount = Mount::Plugins.new(name)\n    when \"scripts\"\n      mount = Mount::Scripts.new(name)\n    when \"tasks\"\n      mount = Mount::Tasks.new(name)\n    when \"locales\"\n      mount = Mount::Locales.new(name)\n    else\n      mount = Mount::File.new(name)\n    end\n    @mounts[name] = mount\n    mount","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/file_serving/configuration/parser.rb#L58-L94","documentation":"Raised by Puppet::FileServing::Configuration::Parser#newmount when a second `[name]` section appears for a mount name that is already in @mounts. Because mounts are keyed by name, a redefinition would silently shadow the first section's paths and ACLs, so the parser rejects it with the previous mount object and the location of the duplicate line.","triggerScenarios":"Two `[modules]` or `[data]` sections in one fileserver.conf; concatenating two config fragments that both define the same mount (e.g. both define `[plugins]`); re-adding a section at the bottom of the file while forgetting one exists earlier.","commonSituations":"Config managed by multiple people or multiple automation tools appending sections; copy-paste of an example block without renaming the header; merging environments after a server consolidation.","solutions":["Search fileserver.conf for repeated `[<name>]` headers and merge the two sections into one, combining their path and allow/deny lines","If the duplicate is accidental, delete the later section","If the two sections really serve different directories, rename one header to a unique mount name and update the `puppet:///<new-name>/...` URIs that reference it"],"exampleFix":"# before (fileserver.conf)\n[data]\n  path /srv/data\n  allow *\n[data]\n  path /srv/other\n  allow *.example.com\n\n# after\n[data]\n  path /srv/data\n  allow *\n[data2]\n  path /srv/other\n  allow *.example.com","handlingStrategy":"validation","validationCode":"def duplicate_mounts?(path)\n  seen = Hash.new(0)\n  File.readlines(path).each do |line|\n    m = line.match(/\\A\\s*\\[([-\\w]+)\\]/)\n    seen[m[1]] += 1 if m\n  end\n  seen.select { |_, n| n > 1 }.keys\nend","typeGuard":null,"tryCatchPattern":"begin\n  parser.parse\nrescue ArgumentError => e\n  raise unless e.message.include?('is already mounted')\n  # e.message names the duplicate mount; merge/remove sections and retry\nend","preventionTips":["Generate fileserver.conf from a single source of truth (template with unique mount keys)","Refuse to append sections programmatically if the header already exists","Review diffs of fileserver.conf for new duplicate headers before deploy"],"tags":["puppet","fileserver","duplicate-mount","argumenterror","ruby"],"backgroundTag":"duplicate-config-section","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}