Custom rewrite rule sends 404 header on multisite

Basically, you are doing one thing wrong, which is actually having a file named manifest.json inside /wp-content/themes/your-theme.

So, first, delete your file /wp-content/themes/your-theme/manifest.json.

Then, in your functions.php file you can have your rewrite rule as:

function fvpd_pwa_rewrite_rules() {
    add_rewrite_endpoint( "manifest", EP_NONE );
    add_rewrite_rule( substr( parse_url( get_template_directory_uri(), PHP_URL_PATH ), 1 ) . "/manifest.json/?$", "index.php?manifest=true", "top" );
}

add_action( "init", "fvpd_pwa_rewrite_rules" );

And your json content as:

// construct a manifest when the user visits {theme_folder}/manifest.json
function fvpd_construct_manifest() {
    if ( get_query_var( "manifest" ) ) {
        $name             = fvpd_get_field( "full_name", "pwa" );
        $short_name       = fvpd_get_field( "short_name", "pwa" );
        $background_color = fvpd_get_field( "background_color", "pwa" );
        $theme_color      = fvpd_get_field( "theme_color", "pwa" );

        $manifest = array(
            "start_url"        => "https://wordpress.stackexchange.com/",
            "display"          => "standalone",
            "name"             => $name ? $name : "Fox Valley Park District - DEV",
            "short_name"       => $short_name ? $short_name : "FVPD",
            "background_color" => $background_color ? $background_color : "#E58F1A",
            "theme_color"      => $theme_color ? $theme_color : "#E58F1A",
            "icons"            => array(
                array(
                    "src"   => get_theme_file_uri( "assets/media/android/splash-icon-512x512.png" ),
                    "type"  => "image/png",
                    "sizes" => "512x512",
                ),
                array(
                    "src"   => get_theme_file_uri( "assets/media/android/launcher-icon-192x192.png" ),
                    "type"  => "image/png",
                    "sizes" => "192x192",
                ),
                array(
                    "src"   => get_theme_file_uri( "assets/media/android/launcher-icon-144x144.png" ),
                    "type"  => "image/png",
                    "sizes" => "144x144",
                ),
                array(
                    "src"   => get_theme_file_uri( "assets/media/android/launcher-icon-96x96.png" ),
                    "type"  => "image/png",
                    "sizes" => "96x96",
                ),
                array(
                    "src"   => get_theme_file_uri( "assets/media/android/launcher-icon-72x72.png" ),
                    "type"  => "image/png",
                    "sizes" => "72x72",
                ),
                array(
                    "src"   => get_theme_file_uri( "assets/media/android/launcher-icon-48x48.png" ),
                    "type"  => "image/png",
                    "sizes" => "48x48",
                ),
            ),
        );

        wp_send_json( $manifest );
    }
}

add_action( "wp", "fvpd_construct_manifest" );

Notice the usage of the WordPress function wp_send_json() which handles for you necessary headers, json converting, etc.

Make sure you flush your permalinks and test the URL which will be something like http://localhost/wp-content/themes/your-theme/manifest.json.

If the above still doesn’t solve your issue it means you are also having trouble setting your web server correctly, NGINX or APACHE, following WordPress standards.