nextcloud / nextcloud/usercontent.apps.nextcloud.com
Screenshot mirror returns an empty body for a quarter of all apps
Nobody has claimed this yet.
- Dominant language
- PHP
- Stars
- 4
- Forks
- 7
- PR merge metrics
- No merged PRs in 30d
Description
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.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the empty responses with the provided curl and jq commands against the usercontent mirror, then trace how fetched images and failed fetches are cached. Verify the behavior using affected examples such as moviedb or crate. Done means affected source URLs return their image body instead of an empty response, with failed fetches retried or not retained as successful empty entries.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- php
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 56/100