{"record":{"id":"c98f67de66297835","repo":"puppetlabs/puppet","slug":"path-must-start-with-a-slash","errorCode":null,"errorMessage":"Path must start with a slash","messagePattern":"Path must start with a slash","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/puppet/http/service/file_server.rb","lineNumber":198,"sourceCode":"      params: {\n        environment: environment,\n        code_id: code_id,\n      }\n    ) do |res|\n      if res.success?\n        res.read_body(&block)\n      end\n    end\n\n    process_response(response)\n\n    response\n  end\n\n  private\n\n  def validate_path(path)\n    raise ArgumentError, \"Path must start with a slash\" unless path =~ PATH_REGEX\n  end\nend\n","sourceCodeStart":180,"sourceCodeEnd":201,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/http/service/file_server.rb#L180-L201","documentation":"Every fileserver service method (get_file_metadata, get_file_content, get_file_skeleton) routes through validate_path, which requires the module-relative path to match PATH_REGEX (%r{^/}). The path must begin with a literal slash, e.g. /modules/mymod/files/config.conf; a path like modules/foo or a full puppet:/// URL is rejected with ArgumentError.","triggerScenarios":"Calling api.get_file_content('modules/apache2/files/httpd.conf') without the leading slash; passing a puppet:///modules/... source URL where a path is expected.","commonSituations":"Reusing a Puppet source URI (puppet:///modules/...) as the path instead of stripping scheme and host; paths built by concatenation where the leading slash was dropped; code ported from the old file_metadata indirector that accepted slightly different formats.","solutions":["Prepend '/' when missing: path = \"/#{path}\" unless path.start_with?('/')","Convert puppet:/// URLs first: strip the scheme/host with Puppet::Util.uri_split (or a regex) and use the path portion","Centralize path construction in one helper that asserts the leading slash"],"exampleFix":"# before (ruby)\napi.get_file_content('modules/apache2/files/httpd.conf') # => ArgumentError\n\n# after\napi.get_file_content('/modules/apache2/files/httpd.conf')","handlingStrategy":"validation","validationCode":"# ruby\ndef normalized_path(path)\n  path = path.sub(%r{\\Apuppet://[^/]*/}, '') if path.start_with?('puppet:')\n  path.start_with?('/') ? path : \"/#{path}\"\nend\npath = normalized_path(path)\napi.get_file_content(path)","typeGuard":"def valid_fileserver_path?(p)\n  p.is_a?(String) && p.start_with?('/')\nend","tryCatchPattern":"begin\n  api.get_file_content(path)\nrescue ArgumentError => e\n  raise unless e.message.include?('slash')\n  api.get_file_content(\"/#{path}\")\nend","preventionTips":["Convert puppet:/// source URIs to module paths with a single helper before hitting the fileserver service","Never build fileserver paths by concatenation without asserting the leading slash","Cover every path your code sends in a routing-level test"],"tags":["puppet-http","fileserver","path-validation","argument-error"],"backgroundTag":"invalid-path-format","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}