nextcloud/server · error · OCSNotFoundException
Media file not found
Error message
Media file not found
What it means
OCSNotFoundException (HTTP 404) thrown by DiscoverController::mediaImage when fetching or storing the remote media file fails: the HTTP client get($fileName) throws (unreachable host, 404, timeout) or storing into the appdata folder via newFile fails (disk full, no appdata). The catch wraps any Throwable into this single 'Media file not found' response and logs a warning with the media_src.
Source
Thrown at apps/appstore/lib/Controller/DiscoverController.php:138
24,
60 * 60,
$user,
);
if (!$this->checkCanDownloadMedia($fileName)) {
$this->logger->warning('Tried to load media files for app discover section from untrusted source');
throw new OCSBadRequestException('Untrusted media source');
}
try {
$client = $this->clientService->newClient();
$fileResponse = $client->get($fileName);
$contentType = $fileResponse->getHeader('Content-Type');
$extension = $info['extension'] ?? '';
$file = $folder->newFile($hashName . '.' . base64_encode($contentType) . '.' . $extension, $fileResponse->getBody());
} catch (\Throwable $e) {
$this->logger->warning('Could not load media file for app discover section', ['media_src' => $fileName, 'exception' => $e]);
throw new OCSNotFoundException('Media file not found');
}
} else {
// File was found so we can get the content type from the file name
$contentType = base64_decode(explode('.', $file->getName())[1] ?? '');
}
$response = new FileDisplayResponse($file, Http::STATUS_OK, ['Content-Type' => $contentType]);
// cache for 7 days
$response->cacheFor(604800, false, true);
return $response;
}
private function checkCanDownloadMedia(string $filename): bool {
$urlInfo = parse_url($filename);
if (!isset($urlInfo['host']) || !isset($urlInfo['path'])) {
return false;
}
View on GitHub (pinned to ecdeb153ff)
Solutions
- Retry later if the app store endpoint was transiently unavailable (the response is cached, so a later successful fetch repairs it)
- From the server host, verify the failing media_src URL is reachable (curl) — if egress is blocked, allow it
- Check the warning log entry 'Could not load media file for app discover section' for the exact media_src and exception
- If appdata is broken, ensure the folder exists and is writable; a successful refetch will repopulate it
Defensive patterns
Strategy: retry
Try / catch
async function fetchDiscoverMedia(url: string, attempts = 3) {
for (let i = 0; i < attempts; i++) {
try {
return await axios.get(url)
} catch (e) {
if (i === attempts - 1) {
// 404 'Media file not found' — log and fall back to a placeholder image
return PLACEHOLDER
}
await new Promise((r) => setTimeout(r, 2 ** i * 500)) // backoff before retry
}
}
} Prevention
- Treat discover media as best-effort: cache successes and keep a placeholder for failures
- Ensure the server can reach the appstore media hosts (egress rules) so first fetches succeed
- Watch the 'Could not load media file' warning in the log to spot systematic egress problems
When it happens
Trigger: Discover section requesting a screenshot whose remote URL is dead (removed from CDN), the app store host unreachable from the server (firewall/egress rules), DNS failure, or the appdata folder for discover media missing/not writable.
Common situations: App store CDN hiccups; servers with restricted outbound traffic; cached app metadata referencing screenshots that the publisher deleted; appdata on a full/read-only volume.
Related errors
- Untrusted media source
- could not enable app
- could not disable app
- could not remove app
- could not update app
AI-assisted analysis of nextcloud/server@ecdeb153ff (2026-08-17).
Data as JSON: /api/errors/dd06aadc858f12a2.
Report an issue: GitHub.