arsduo/koala · error · Koala::KoalaError

Invalid arguments to initialize an UploadableIO

Error message

Invalid arguments to initialize an UploadableIO

What it means

Koala::HTTPService::UploadableIO wraps a media source for multipart upload. Its constructor tries five parse strategies in order — Rails ActionDispatch::Http::UploadedFile, a Sinatra-style {tempfile:, type:} hash, File/Tempfile, a String path, and any object responding to #read — and raises Koala::KoalaError ('Invalid arguments to initialize an UploadableIO') when none of them sets @io_or_path (lib/koala/http_service/uploadable_io.rb:17). The argument was nil or a type Koala cannot treat as a file. You normally hit it indirectly: put_picture/put_video forward their source into UploadableIO.

Source

Thrown at lib/koala/http_service/uploadable_io.rb:17

require "tempfile"

module Koala
  module HTTPService
    class UploadableIO
      attr_reader :io_or_path, :content_type, :filename

      def initialize(io_or_path_or_mixed, content_type = nil, filename = nil)
        # see if we got the right inputs
        parse_init_mixed_param io_or_path_or_mixed, content_type

        # filename is used in the Ads API
        # if it's provided, take precedence over the detected filename
        # otherwise, fall back to a dummy name
        @filename = filename || @filename || "koala-io-file.dum"

        raise KoalaError.new("Invalid arguments to initialize an UploadableIO") unless @io_or_path
        raise KoalaError.new("Unable to determine MIME type for UploadableIO") if !@content_type
      end

      def to_upload_io
        UploadIO.new(@io_or_path, @content_type, @filename)
      end

      def to_file
        @io_or_path.is_a?(String) ? File.open(@io_or_path) : @io_or_path
      end

      def self.binary_content?(content)
        content.is_a?(UploadableIO) || DETECTION_STRATEGIES.detect {|method| send(method, content)}
      end

      private
      DETECTION_STRATEGIES = [
        :sinatra_param?,

View on GitHub (pinned to 47d052063e)

Solutions

  1. Pass a real media source: a path String, File/Tempfile, an IO-like object (StringIO), an ActionDispatch::Http::UploadedFile, or a Sinatra {tempfile:, type:} hash with symbol keys
  2. Check the upload param for nil at the controller edge (raise 'choose a file') before calling put_picture
  3. Unwrap ORM/attachment objects — give Koala the underlying File or path (e.g. uploader.file.file), not the uploader itself
  4. In Sinatra, symbolize the file param hash keys before passing

Example fix

# before
api.put_picture(params[:photo]) # params[:photo] is nil when no file was selected

# after
file = params[:photo]
raise 'Please choose a file' if file.nil?
api.put_picture(file) # ActionDispatch::Http::UploadedFile is recognized natively
Defensive patterns

Strategy: validation

Validate before calling

def uploadable_source?(obj)
  obj.is_a?(String) || obj.is_a?(File) || obj.is_a?(Tempfile) || obj.respond_to?(:read) ||
    (obj.respond_to?(:content_type) && obj.respond_to?(:tempfile)) || # Rails ActionDispatch::Http::UploadedFile
    (obj.is_a?(Hash) && obj.key?(:tempfile) && obj.key?(:type))        # Sinatra param hash
end

raise ArgumentError, 'media must be a path, File, IO, or uploaded-file param' unless uploadable_source?(media)
api.put_picture(media)

Type guard

def uploadable_source?(obj)
  obj.is_a?(String) || obj.is_a?(File) || obj.is_a?(Tempfile) || obj.respond_to?(:read) ||
    (obj.respond_to?(:content_type) && obj.respond_to?(:tempfile)) ||
    (obj.is_a?(Hash) && obj.key?(:tempfile) && obj.key?(:type))
end
# uploadable_source?(params[:photo]) => true / false

Try / catch

begin
  api.put_picture(media)
rescue Koala::KoalaError => e
  # raised before any HTTP traffic — the media argument shape is wrong
  render json: {error: "Unsupported file source: #{media.class}"}, status: 400
end

Prevention

When it happens

Trigger: api.put_picture(nil) or api.put_picture(params[:missing_file_key]); passing an Integer or arbitrary object; a Hash lacking :tempfile or :type (e.g. Sinatra params with string keys 'tempfile'/'type'); a Paperclip/CarrierWave uploader object instead of its underlying File or path.

Common situations: A Rails form rendered without the file field so params[:photo] is nil; attachment wrappers passed instead of the raw file; Sinatra params forwarded with string keys where the parser requires symbols; refactors that pass a filename variable that was never assigned.

Related errors


AI-assisted analysis of arsduo/koala@47d052063e (2026-08-23). Data as JSON: /api/errors/039357aa3dc92e36. Report an issue: GitHub.