The problem is in Ext.data.request.Form. In the normal Ext.Ajax.request() case, the form is already in the DOM so this code ends up moving it to the end of body and then removing it completely.

Code:
    upload: function(form, url, params, options) {
        form = Ext.getDom(form);
        options = options || {};
 
        var frameDom = document.createElement('iframe'),
            frame = Ext.get(frameDom),
            id = frame.id,
            hiddens = [],
            encoding = 'multipart/form-data',
            buf = {
                target: form.target,
                method: form.method,
                encoding: form.encoding,
                enctype: form.enctype,
                action: form.action
            },
            addField = function(name, value) {
                hiddenItem = document.createElement('input');
                Ext.fly(hiddenItem).set({
                    type: 'hidden',
                    value: value,
                    name: name
                });
                form.appendChild(hiddenItem);
                hiddens.push(hiddenItem);
            },
            hiddenItem, obj, value, name, vLen, v, hLen, h, request;
 
        /*
         * Originally this behaviour was modified for Opera 10 to apply the secure URL after
         * the frame had been added to the document. It seems this has since been corrected in
         * Opera so the behaviour has been reverted, the URL will be set before being added.
         */
        frame.set({
            name: id,
            cls: Ext.baseCSSPrefix + 'hidden-display',
            src: Ext.SSL_SECURE_URL,
            tabIndex: -1
        });
 
        document.body.appendChild(frameDom);
        document.body.appendChild(form);     <----- Why?
 
        // This is required so that IE doesn't pop the response up in a new window. 
        if (document.frames) {
            document.frames[id].name = id;
        }
 
        Ext.fly(form).set({
            target: id,
            method: 'POST',
            enctype: encoding,
            encoding: encoding,
            action: url || buf.action
        });
 
        // add dynamic params 
        if (params) {
            obj = Ext.Object.fromQueryString(params) || {};
 
            for (name in obj) {
                if (obj.hasOwnProperty(name)) {
                    value = obj[name];
                    if (Ext.isArray(value)) {
                        vLen = value.length;
                        for (v = 0; v < vLen; v++) {
                            addField(name, value[v]);
                        }
                    } else {
                        addField(name, value);
                    }
                }
            }
        }
        
        this.frame = frame;
        
        frame.on({
            load: this.onComplete,
            scope: this,
            // Opera introduces multiple 'load' events, so account for extras as well 
            single: !Ext.isOpera
        });
 
        form.submit();
        document.body.removeChild(form);  <--------------- Why
 
        // Restore form to previous settings 
        Ext.fly(form).set(buf);
 
        for (hLen = hiddens.length, h = 0; h < hLen; h++) {
            Ext.removeNode(hiddens[h]);
        }
 
        return form;
    },