{"record":{"id":"cf9a771da0edf940","repo":"ruby-grape/grape","slug":"argument-must-be-a-file-path","errorCode":null,"errorMessage":"Argument must be a file path","messagePattern":"Argument must be a file path","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/grape/dsl/inside_route.rb","lineNumber":125,"sourceCode":"      #   end\n      #\n      #   DELETE /12 # => 204 No Content, \"\"\n      def return_no_content\n        body false\n      end\n\n      # Allows you to send a file to the client via sendfile.\n      #\n      # @example\n      #   get '/file' do\n      #     sendfile FileStreamer.new(...)\n      #   end\n      #\n      #   GET /file # => \"contents of file\"\n      def sendfile(value = nil)\n        return stream if value.nil?\n\n        raise ArgumentError, 'Argument must be a file path' unless value.is_a?(String)\n\n        file_body = Grape::ServeStream::FileBody.new(value)\n        @stream = Grape::ServeStream::StreamResponse.new(file_body)\n      end\n\n      # Allows you to define the response as a streamable object.\n      #\n      # If Content-Length and Transfer-Encoding are blank (among other conditions),\n      # Rack assumes this response can be streamed in chunks.\n      #\n      # @example\n      #   get '/stream' do\n      #     stream FileStreamer.new(...)\n      #   end\n      #\n      #   GET /stream # => \"chunked contents of file\"\n      #\n      # See:","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/ruby-grape/grape/blob/22d7975629846a3c0c7bd2b34e140a7a1b4af8f6/lib/grape/dsl/inside_route.rb#L107-L143","documentation":"`sendfile` hands a file to the client via Grape::ServeStream::FileBody, which needs a filesystem path it can open lazily. The guard requires the argument to be a String; File handles, Pathname objects, or any IO-like object raise 'Argument must be a file path'. Note this is stricter than Rack, which also accepts objects responding to to_path.","triggerScenarios":"`sendfile File.open('/tmp/x.csv')` (File object). `sendfile Pathname.new('/tmp/x.csv')` (Pathname). `sendfile tempfile` where tempfile is a Tempfile from a multipart upload instead of `tempfile.path`.","commonSituations":"Streaming generated reports or uploads stored on disk. Reusing Rack/Sinatra send_file idioms that accept Pathname or File. Passing the result of another API that returns a file handle.","solutions":["Pass the path string: `sendfile file.path` for File/Tempfile, `sendfile pathname.to_s` for Pathname.","If you have an IO object rather than a path, use the `stream` helper with an each-responding wrapper instead of `sendfile`."],"exampleFix":"# before\nsendfile Pathname.new('/files/report.pdf') # raises\nsendfile uploaded_tempfile            # Tempfile object raises\n\n# after\nsendfile Pathname.new('/files/report.pdf').to_s\nsendfile uploaded_tempfile.path","handlingStrategy":"type-guard","validationCode":"path = case value\n       when String then value\n       when File, Tempfile then value.path\n       when Pathname then value.to_s\n       else raise ArgumentError, \"cannot derive a file path from #{value.class}\"\n       end\nsendfile path","typeGuard":"def sendfile_path?(value) = value.is_a?(String) && !value.empty?","tryCatchPattern":null,"preventionTips":["Standardize on `sendfile obj.path` / `sendfile obj.to_s` everywhere in the codebase.","Use the `stream` helper for IO objects that have no path.","Add a spec for the file-serving endpoint in CI so argument-type regressions surface early."],"tags":["grape","sendfile","file-path","argument-type","streaming"],"backgroundTag":"invalid-file-argument","analyzedSha":"22d7975629846a3c0c7bd2b34e140a7a1b4af8f6","analyzedAt":"2026-08-21T17:03:54.627Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}