{"record":{"id":"be0a896a3d417b82","repo":"puppetlabs/puppet","slug":"relative-paths-must-not-be-fully-qualified","errorCode":null,"errorMessage":"Relative paths must not be fully qualified","messagePattern":"Relative paths must not be fully qualified","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/puppet/file_serving/base.rb","lineNumber":72,"sourceCode":"\n    @links = value\n  end\n\n  # Set our base path.\n  attr_reader :path\n\n  def path=(path)\n    raise ArgumentError, _(\"Paths must be fully qualified\") unless Puppet::FileServing::Base.absolute?(path)\n\n    @path = path\n  end\n\n  # Set a relative path; this is used for recursion, and sets\n  # the file's path relative to the initial recursion point.\n  attr_reader :relative_path\n\n  def relative_path=(path)\n    raise ArgumentError, _(\"Relative paths must not be fully qualified\") if Puppet::FileServing::Base.absolute?(path)\n\n    @relative_path = path\n  end\n\n  # Stat our file, using the appropriate link-sensitive method.\n  def stat\n    @stat_method ||= links == :manage ? :lstat : :stat\n    Puppet::FileSystem.send(@stat_method, full_path)\n  end\n\n  def to_data_hash\n    {\n      'path' => @path,\n      'relative_path' => @relative_path,\n      'links' => @links.to_s\n    }\n  end\n","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/file_serving/base.rb#L54-L90","documentation":"Puppet::FileServing::Base#relative_path= stores a file's path relative to the recursion root and is the mirror of path=: it raises ArgumentError when handed an absolute path (checked with the same absolute? helper). It is set internally while recursively serving directories; custom code that reuses FileServing::Base and passes a full path into relative_path hits this guard.","triggerScenarios":"Constructing or monkey-patching file-serving/metadata objects and assigning a fully qualified path to relative_path=; recursion helpers that mix up full_path and the relative offset.","commonSituations":"Writing custom providers, indirections, or tests that build on Puppet::FileServing::Base; porting logic that computed paths differently.","solutions":["Pass only the portion below the recursion root, e.g. 'subdir/file.txt', not '/mnt/root/subdir/file.txt'","Compute it explicitly: Pathname.new(full).relative_path_from(Pathname.new(root)).to_s","If you truly have an absolute location, assign it with path= instead"],"exampleFix":"# before\nobj.relative_path = '/srv/files/subdir/a.txt'\n# after\nobj.path = '/srv/files'\nobj.relative_path = 'subdir/a.txt'","handlingStrategy":"validation","validationCode":"def rel_path(root, full)\n  r = Pathname.new(root)\n  Pathname.new(full).expand_path.relative_path_from(r.expand_path).to_s\nend\nobj.relative_path = rel_path('/srv/files', '/srv/files/subdir/a.txt') # => 'subdir/a.txt'","typeGuard":"def relative_sub_path?(p)\n  p.is_a?(String) && !p.empty? && !Puppet::FileServing::Base.absolute?(p)\nend","tryCatchPattern":null,"preventionTips":["Always derive relative_path from a known root with Pathname#relative_path_from instead of passing user input","Reserve absolute locations for path=; keep relative_path strictly below the recursion root"],"tags":["puppet","file-serving","path-validation","recursion"],"backgroundTag":"path-must-be-relative","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}