How to restrict wp-admin and prevent upload errors

You just need one extra thing for this.

Here is the code I typically use to do what you are doing:

function pws_block_admin() {

    if (
        // Look for the presence of /wp-admin/ in the url
        stripos($_SERVER['REQUEST_URI'],'/wp-admin/') !== false
        &&
        // Allow calls to async-upload.php
        stripos($_SERVER['REQUEST_URI'],'async-upload.php') === false
        &&
        // Allow calls to admin-ajax.php
        stripos($_SERVER['REQUEST_URI'],'admin-ajax.php') === false
    ) {
        if ( !current_user_can('manage_options') ) {
            $redirect_to = home_url();
            wp_redirect($redirect_to, 302);
        }
    }
}
add_action('admin_init', 'pws_block_admin', 0);

It looks like you are just missing the exclusion for allowing async-upload.php to work.