WooCommerce CSV Exports Are Silently Broken with S3 Uploads
If you use WooCommerce with S3 Uploads, your analytics exports might be quietly failing and not sending any emails, despite Action Scheduler saying the job was complete.
From Analytics > Revenue, you click the Download button. The network tab shows the POST to /wc-analytics/reports/revenue/export with a payload:
{
"report_args": {
"interval": "day",
"orderby": "date",
"order": "desc",
"page": 1,
"per_page": 25,
"after": "2025-01-01T00:00:00",
"before": "2025-12-31T23:59:59"
},
"email": true
}
The response includes an export_id and a status link:
{
"message": "Your report file is being generated.",
"export_id": "12312312312312",
"_links": {
"status": [
{
"href": "https://example.com/wp-json/wc-analytics/reports/revenue/export/12312312312312/status"
}
]
}
}
But then no email is sent.
Checking WooCommerce > Status > Scheduled Actions, the woocommerce_admin_report_export batch jobs show “Complete.” The woocommerce_admin_email_report_download_link action ran and everything looks healthy in the admin.
Since the email never arrived, we dug into the export status endpoint code and found that when percent_complete reaches 100, it constructs a download_url from the export ID and report type. Using the export ID from the Scheduled Actions args, we manually hit:
/wp-admin/?action=woocommerce_admin_download_report_csv&filename=wc-revenue-report-export-12312312312312
A CSV downloaded, but with only headers:
Date,Orders,"Gross sales",Returns,Coupons,"Net sales",Taxes,Shipping,"Total sales"
Why it’s silent
WooCommerce’s batch exporter writes CSV data in WC_CSV_Batch_Exporter::write_csv_data(). The file operations use @fopen and @file_put_contents with silenced errors. When the write fails, no exception is thrown, nothing is logged, and the Action Scheduler job just “completes” with zero data written.
What’s happening
write_csv_data() opens the CSV file with fopen mode a+ (read + append):
$fopen_mode = apply_filters( 'woocommerce_csv_exporter_fopen_mode', 'a+' );
$fp = fopen( $this->get_file_path(), $fopen_mode );
When you’re running S3 Uploads, wp_upload_dir() returns an s3:// path. The S3 stream wrapper only supports r, w, a, and x — the + variants require seekable streams, which S3 objects aren’t. So fopen fails, $fp is false, and the data is never written.
When we tried generating the export via WP-CLI, the errors were no longer silenced:
PHP Warning: Mode not supported: a+. Use one 'r', 'w', 'a', or 'x'.
in /var/www/public/app/mu-plugins/s3-uploads/inc/class-stream-wrapper.php on line 985
PHP Warning: fopen(s3://bucket/uploads/woocommerce_uploads/reports/wc-revenue-report-export.csv):
Failed to open stream: "S3_Uploads\Stream_Wrapper::stream_open" call failed
in /var/www/public/app/plugins/woocommerce/includes/export/abstract-wc-csv-batch-exporter.php on line 151
Fixing the CSV generation
WooCommerce added a hook in 6.8.0 via woocommerce/woocommerce#33652 that defaults to a+.
To fix the CSV generation, you’ll have to add a filter that overrides this to a, which is S3-compatible:
add_filter('woocommerce_csv_exporter_fopen_mode', fn () => 'a');
If you’re routing uploads through any S3 stream wrapper, you’re affected by this. The exports will always produce headers-only files with no data rows and the email is never sent.
Issue submitted to WooCommerce: https://github.com/woocommerce/woocommerce/issues/63835