Available — part-time slots from Q4 2026 UK · Remote BST · GMT+1
All fixes
F/08 10 min read reviewed Sep 2026· Strapi 5

Uploads return 200 but the file 404s

TL;DR

The upload succeeds. The API returns 200, the entry saves, and the file will not load: the URL 404s, or it renders as a broken image in the admin. This is almost never data loss. It is usually the upload provider quietly falling back to local storage in production, or existing files rows still pointing at the old host after a provider change. Confirm which before you touch anything: open the raw file URL outside the admin, check whether only pre-existing media is broken, and read what the files table actually says.

00· Before anything

First: three questions, in order

This symptom has several distinct causes that look identical from the entry screen. Three questions separate them before you change anything.

One: does the raw file URL load in a new tab, outside the admin? If it loads there but not in the admin, the file is fine and the admin cannot render it, which points at CSP. Two: is it only pre-existing media that is broken, while new uploads work? That asymmetry points at the files table, not at config. Three: what does the table actually say.

sql
SELECT url, provider FROM files LIMIT 5;

Run that sequence before editing any config. It resolves almost every version of this without changing a thing, and it tells you which of the causes below you are actually in.

Likely causes · The order I check them

bars = diagnostic order from experience, not measured frequency

Cause 01 of 01

The upload provider isn't configured for production, so Strapi uses local storage

Symptom

Files upload and work for a while, then vanish, often after a deploy or a restart. New uploads meet the same fate.

How to confirm

Check the provider column in the files table. If it says local in production, you found it. Cross-check against your config with a resolved-config log at boot.

Why it happens

When the provider is not resolved for the production environment, Strapi falls back to the local provider. On an ephemeral container filesystem the file is written, served once, and gone at the next restart.

The fix

Configure the upload provider in config/env/production/plugins, not just config/plugins. This is the same root cause as config being ignored in production.

The provider falling back to local on misconfiguration is observed behaviour, not documented. The ephemeral-filesystem half is documented, but only in the FAQ and only for self-hosted PaaS.

02

Do not apply the ephemeral-filesystem framing to Strapi Cloud. Cloud asset storage is a persistent, billed resource, so a 200-then-404 there has a different mechanism, usually the files-table or CSP cause below.

Likely causes · The order I check them

bars = diagnostic order from experience, not measured frequency

Cause 01 of 04

The provider changed, but the files table didn't

Symptom

New uploads work. Everything uploaded before the change 404s. That asymmetry is the tell.

How to confirm

SELECT url, provider FROM files LIMIT 5. If url, formats and provider still point at the old host or provider for existing rows, this is it.

Why it happens

Changing the provider does not rewrite existing files rows. Their stored url, formats and provider still point at wherever they were uploaded.

The fix

Rewrite the files table to the new host and provider. Back up the table first, then run it in a transaction:

sql
update files set url = replace(url, '<old-host>', '<new-host>') where url is not null;
update files set formats = replace(formats::TEXT, '<old-host>', '<new-host>')::jsonb where formats is not null;
update files set provider = replace(provider, '<old-provider>', '<new-provider>') where provider is not null;

A provider change leaving existing rows untouched is observed behaviour, not documented. Check five rows before and after you commit.

07

What's documented, and what's observed

Two of the most useful facts here are not in the documentation. The provider falling back to local on misconfiguration, and a provider change leaving existing files rows untouched, are both observed behaviour: reliable, reproducible, and worth knowing, but not written down. The ephemeral-filesystem behaviour is documented, though only in the FAQ and only for self-hosted PaaS. Treat the SQL rewrite as a support-grade workaround: back up the table, run it in a transaction, and check five rows before and after.

Common questions

Diagnosed everything and still stuck?

S/01 — Performance & Architecture Rescue.

A fixed-scope week that finds the cause and fixes what's causing it.