apps.json hands clients raw screenshot URLs; a Nextcloud instance never fetches those
itself but asks the mirror at
https://usercontent.apps.nextcloud.com/<base64 of the URL as it appears in apps.json>.
For a large share of apps that mirror answers HTTP 200 with an empty body, while the
source URL serves the image fine. Instances therefore show no screenshot in the app list.
The store website is unaffected — it embeds the source URL directly.
Steps to reproduce
curl -sL --compressed -o apps.json https://apps.nextcloud.com/api/v1/platform/34.0.0/apps.json
jq -r '.[] | .id as $i | .screenshots[]? | $i + "\t" + (.url|@base64)' apps.json |
while IFS=$'\t' read -r id b64; do
n=$(curl -s "https://usercontent.apps.nextcloud.com/$b64" | head -c 20 | wc -c)
[ "$n" -eq 0 ] && echo "empty: $id"
done
The base64 key must be built from the URL string exactly as it appears in apps.json,
including any surrounding whitespace — several apps write <screenshot> across multiple
lines in info.xml, and that whitespace is part of the key. (Whitespace itself is not the
bug: 80 of the 88 whitespace-carrying URLs are mirrored correctly.)
Expected behaviour
The mirror serves the image, as it does for the majority of apps.
Actual behaviour
Measured 2026-09-09 against /api/v1/platform/34.0.0/apps.json:
| result |
screenshot URLs |
| image delivered |
763 |
| empty body (0 bytes) |
318 |
body File not found (14 bytes) |
5 |
| total |
1086 (from 381 apps) |
97 of 381 apps with screenshots have at least one empty image.
Examples: moviedb, crate, n8n_sync, homecheck, maintenancecheck, twofactor_email,
folder_protection, kanso, integration_pexip, agora, llmchat, launchpad.
A random sample of ten affected URLs was fetched from their source: all ten returned
HTTP 200 with the full image (94–630 KB). So the source is not the problem.
Guess
A first fetch that failed appears to be cached as an empty entry and never retried.
Re-fetching on an empty cache entry, or not caching failures at all, would fix it.
apps.jsonhands clients raw screenshot URLs; a Nextcloud instance never fetches thoseitself but asks the mirror at
https://usercontent.apps.nextcloud.com/<base64 of the URL as it appears in apps.json>.For a large share of apps that mirror answers HTTP 200 with an empty body, while the
source URL serves the image fine. Instances therefore show no screenshot in the app list.
The store website is unaffected — it embeds the source URL directly.
Steps to reproduce
The base64 key must be built from the URL string exactly as it appears in apps.json,
including any surrounding whitespace — several apps write
<screenshot>across multiplelines in
info.xml, and that whitespace is part of the key. (Whitespace itself is not thebug: 80 of the 88 whitespace-carrying URLs are mirrored correctly.)
Expected behaviour
The mirror serves the image, as it does for the majority of apps.
Actual behaviour
Measured 2026-09-09 against
/api/v1/platform/34.0.0/apps.json:File not found(14 bytes)97 of 381 apps with screenshots have at least one empty image.
Examples:
moviedb,crate,n8n_sync,homecheck,maintenancecheck,twofactor_email,folder_protection,kanso,integration_pexip,agora,llmchat,launchpad.A random sample of ten affected URLs was fetched from their source: all ten returned
HTTP 200 with the full image (94–630 KB). So the source is not the problem.
Guess
A first fetch that failed appears to be cached as an empty entry and never retried.
Re-fetching on an empty cache entry, or not caching failures at all, would fix it.