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

  1. Send the exact appId from the installed-apps listing; verify it passes cleanAppId() (alphanumeric, dashes)
  2. Confirm the app is not in the always-enabled set — those cannot be disabled
  3. Run `occ app:disable <appId>` to reproduce with a full stack trace
  4. 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

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.