nextcloud/server · error · OCSException
could not disable app
Error message
could not disable app
What it means
OCSException (HTTP 500) thrown by ApiController::disableApp when cleanAppId() rejects the id (invalid characters/format), removeOverwriteNextcloudRequirement() fails, or appManager->disableApp() throws. The caught \Exception is logged as 'could not disable app' and chained, so nextcloud.log holds the underlying reason.
Source
Thrown at apps/appstore/lib/Controller/ApiController.php:212
*
* @param string $appId - The app to disable
*
* @return DataResponse<Http::STATUS_OK, array{}, array{}>
* @throws OCSException - if the app could not be disabled
*
* 200: App successfully disabled
*/
#[PasswordConfirmationRequired(strict: false)]
#[ApiRoute(verb: 'POST', url: '/api/v1/apps/disable')]
public function disableApp(string $appId): DataResponse {
try {
$appId = $this->appManager->cleanAppId($appId);
$this->appManager->removeOverwriteNextcloudRequirement($appId);
$this->appManager->disableApp($appId);
return new DataResponse([]);
} catch (\Exception $exception) {
$this->logger->error('could not disable app', ['exception' => $exception]);
throw new OCSException('could not disable app', Http::STATUS_INTERNAL_SERVER_ERROR, $exception);
}
}
/**
* Uninstall an app.
*
* @param string $appId - The app to uninstall
* @return DataResponse<Http::STATUS_OK, array{}, array{}>
* @throws OCSException - if the app could not be uninstalled
*
* 200: App successfully uninstalled
*/
#[PasswordConfirmationRequired(strict: true)]
#[ApiRoute(verb: 'POST', url: '/api/v1/apps/uninstall')]
public function uninstallApp(string $appId): DataResponse {
$appId = $this->appManager->cleanAppId($appId);
if ($this->appManager->isEnabledForAnyone($appId)) {
$this->disableApp($appId);View on GitHub (pinned to ecdeb153ff)
Solutions
- Send the exact appId from the installed-apps listing; verify it passes cleanAppId() (alphanumeric, dashes)
- Confirm the app is not in the always-enabled set — those cannot be disabled
- Run `occ app:disable <appId>` to reproduce with a full stack trace
- Check nextcloud.log for the chained 'could not disable app' exception
Defensive patterns
Strategy: try-catch
Validate before calling
// Only attempt disabling apps that are actually installed and disableable
const apps = (await axios.get(generateOcsUrl('/apps/appstore/apps/list'))).data
const target = apps.find((a) => a.id === appId)
if (!target || !target.removableFromList) {
// skip the call — it would 500
} Try / catch
try {
await axios.post(generateOcsUrl('/apps/appstore/apps/disable'), { appId })
} catch (e) {
// 500 'could not disable app' — check nextcloud.log; verify appId validity and that the app may be disabled
} Prevention
- Send appIds exactly as returned by the apps listing (cleanAppId rejects other formats)
- Remember always-enabled shipped apps cannot be disabled
- Reproduce with `occ app:disable` for the full stack trace
When it happens
Trigger: POST /ocs/appstore/apps/disable with a malformed appId (cleanAppId throws on invalid names), attempting to disable an app that the platform forbids disabling (always-enabled shipped apps), or backend/database errors during the disable transition.
Common situations: Frontend sending a stale or manipulated app id; admin trying to disable core apps that cannot be disabled (they can only be removed/uninstalled where allowed); database locked mid-operation; app whose disable hook throws.
Related errors
AI-assisted analysis of nextcloud/server@ecdeb153ff (2026-08-17).
Data as JSON: /api/errors/dcd4618bfd9dec7f.
Report an issue: GitHub.