nextcloud / nextcloud/usercontent.apps.nextcloud.com

Screenshot mirror returns an empty body for a quarter of all apps

Open
#26 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.