nextcloud/server · warning · OCSNotFoundException
Bundle not found
Error message
Bundle not found
What it means
OCSNotFoundException (HTTP 404) thrown by ApiController::enableBundle when bundleFetcher->getBundleByIdentifier($bundleId) raises BadMethodCallException, i.e. no app bundle with that identifier is known to the server. Bundles are server-side defined groups of apps (shipped with the appstore data), so the id space depends on the Nextcloud version.
Source
Thrown at apps/appstore/lib/Controller/ApiController.php:290
/**
* Enable all apps of a bundle
*
* @param string $bundleId - The bundle to enable
* @return DataResponse<Http::STATUS_OK, array{}, array{}>
* @throws OCSException - if the bundle, or one app within, could not be enabled
*
* 200: Bundle successfully enabled
*/
#[PasswordConfirmationRequired(strict: true)]
#[ApiRoute(verb: 'POST', url: '/api/v1/bundles/enable')]
public function enableBundle(string $bundleId): DataResponse {
try {
$bundle = $this->bundleFetcher->getBundleByIdentifier($bundleId);
$this->config->setSystemValue('maintenance', true);
$this->installer->installAppBundle($bundle);
} catch (\BadMethodCallException $e) {
throw new OCSNotFoundException('Bundle not found', $e);
} catch (\Exception $exception) {
$this->logger->error('could not enable bundle', ['bundleId' => $bundleId, 'exception' => $exception]);
throw new OCSException('could not enable bundle', Http::STATUS_INTERNAL_SERVER_ERROR, $exception);
} finally {
$this->config->setSystemValue('maintenance', false);
}
return new DataResponse([]);
}
/**
* Convert URL to proxied URL so CSP is no problem
*/
private function createProxyPreviewUrl(string $url): string {
if ($url === '') {
return '';
}
View on GitHub (pinned to ecdeb153ff)
Solutions
- Refetch the current bundle list from the apps/bundles listing endpoint and use ids from that response
- Handle the 404 by refreshing the App Store view instead of retrying the same id
- After a server upgrade, reload the settings page so stale bundle ids are discarded
- Verify the id casing/format matches exactly
Defensive patterns
Strategy: validation
Validate before calling
// Validate bundleId against the server's current bundle list
const bundles = (await axios.get(generateOcsUrl('/apps/appstore/bundles/list'))).data
if (!bundles.some((b) => b.id === bundleId)) {
throw new Error(`Unknown bundle: ${bundleId}`)
}
await axios.post(generateOcsUrl('/apps/appstore/bundles/enable'), { bundleId }) Try / catch
try {
await axios.post(generateOcsUrl('/apps/appstore/bundles/enable'), { bundleId })
} catch (e) {
if (e?.response?.status === 404) {
// 'Bundle not found' — refetch the bundle list and re-render
} else throw e
} Prevention
- Always take bundle ids from a fresh listing; never hardcode or cache across upgrades
- Handle 404 by refreshing the view instead of retrying the stale id
When it happens
Trigger: POST /ocs/appstore/bundles/enable with a bundleId that does not exist: id from a cached frontend bundle list of an older Nextcloud version, hand-typed/typo'd id, or an appstore backend that does not provide bundles.
Common situations: Browser tab left open across a server upgrade — the cached bundle list no longer matches; scripts automating bundle enable with hardcoded ids; third-party/custom appstore deployments without bundle metadata.
Related errors
- could not enable bundle
- 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/25c29675bdad0cc9.
Report an issue: GitHub.