RemarkableCloud

External images import as 0-byte files

Product or media imports create files with the right name but no content. This is almost always the remote image host rejecting requests that carry no User-Agent header.

You run an import (a product feed, a dropshipping integration, a migration tool, a “download external images” routine) and the images arrive empty: the file appears in wp-content/uploads with the correct filename, but its size is 0 bytes. The media library shows a broken thumbnail.

A strong clue that points to this exact cause: the plugin can preview or search the image fine, and only the import produces empty files.

Why this happens

Most import plugins fetch images with PHP’s file_get_contents(). That function sends no User-Agent header unless the code explicitly sets one, because PHP’s built-in default for the user_agent setting is empty.

Many image hosts sit behind a CDN or WAF (CloudFront, Cloudflare, Akamai and similar) configured to reject requests with a missing or empty User-Agent, since that pattern is typical of scrapers and bots. Those requests get a 403 Forbidden instead of the image.

The plugin then does something like this, without checking whether the download succeeded:

$image_data = file_get_contents( $image_url );
file_put_contents( $file, $image_data );

file_get_contents() returned false, so file_put_contents() writes nothing and you are left with a 0-byte file carrying the right name.

The preview or search feature usually works because that part of the plugin uses wp_remote_get(), WordPress’s own HTTP API, which always sends a User-Agent such as WordPress/6.8; https://example.com. Same server, same network, same moment: one request is allowed and the other is refused, purely because of that header.

Empty files here are not caused by folder permissions, disk quota, or `allow_url_fopen`. If those were the problem, no file would be created at all, or the import would raise a write error. A correctly named, zero-byte file means the write worked and the download did not.

Confirming the cause

If you have shell access, request one of the failing image URLs twice, once with a User-Agent and once without:

# With a normal User-Agent
curl -s -o /dev/null -w "%{http_code} %{size_download}\n" "https://cdn.example.com/path/to/image.jpg"

# With an empty User-Agent
curl -s -A "" -o /dev/null -w "%{http_code} %{size_download}\n" "https://cdn.example.com/path/to/image.jpg"

A result of 200 with a real byte count on the first command and 403 with a tiny body on the second confirms it.

How to fix it

1. Report it to the plugin developer (the real fix)

This is a bug in the plugin, and it is theirs to correct. Ask them to download images with WordPress’s HTTP API instead of raw file_get_contents():

// Preferred: WordPress helper, sends a User-Agent and handles errors
$tmp = download_url( $image_url );

// Or, if they keep their own request logic
$response = wp_remote_get( $image_url );
$image_data = wp_remote_retrieve_body( $response );

Ask them to check the result before writing the file, so a failed download reports an error instead of silently producing an empty image.

2. If it is your own code

Set a User-Agent on the request:

$context = stream_context_create( [
    'http' => [ 'header' => "User-Agent: WordPress/6.8\r\n" ],
] );
$image_data = file_get_contents( $image_url, false, $context );

Or set a default for the whole script before the download runs:

ini_set( 'user_agent', 'WordPress/6.8' );

3. If you cannot change the plugin’s code

We can set a default User-Agent at the PHP level for your hosting account, so that every PHP download that would otherwise send an empty header sends a valid one instead. The plugin then works unmodified, and the setting survives plugin updates.

  • Open a ticket from your client area and tell us the affected domain.
  • Include one of the image URLs that is failing, so we can verify the fix against the real source.
  • We apply the setting and confirm that the download returns the complete image instead of 0 bytes.
  • Re-run your import and check that the images now arrive with their full size.
  • This setting is tied to the PHP version your account is currently using. If you later switch versions from your control panel, open a ticket so we can reapply it, otherwise the empty images will come back.

    Cleaning up the empty files

    Existing 0-byte attachments are not repaired by the fix, they simply stop being created. Delete the broken entries from the media library, or remove the affected products, then run the import again so the images are fetched properly.

    To find them over SSH:

    find ~/public_html/wp-content/uploads -type f -size 0 -name '*.jpg' -o -type f -size 0 -name '*.png'

    Review the list before deleting anything, since some plugins legitimately ship empty placeholder files.

    Still stuck? Ask a human, we answer in minutes.