{"record":{"id":"dcd4618bfd9dec7f","repo":"nextcloud/server","slug":"could-not-disable-app","errorCode":null,"errorMessage":"could not disable app","messagePattern":"could not disable app","errorType":"http","errorClass":"OCSException","httpStatus":500,"severity":"error","filePath":"apps/appstore/lib/Controller/ApiController.php","lineNumber":212,"sourceCode":"\t *\n\t * @param string $appId - The app to disable\n\t *\n\t * @return DataResponse<Http::STATUS_OK, array{}, array{}>\n\t * @throws OCSException - if the app could not be disabled\n\t *\n\t * 200: App successfully disabled\n\t */\n\t#[PasswordConfirmationRequired(strict: false)]\n\t#[ApiRoute(verb: 'POST', url: '/api/v1/apps/disable')]\n\tpublic function disableApp(string $appId): DataResponse {\n\t\ttry {\n\t\t\t$appId = $this->appManager->cleanAppId($appId);\n\t\t\t$this->appManager->removeOverwriteNextcloudRequirement($appId);\n\t\t\t$this->appManager->disableApp($appId);\n\t\t\treturn new DataResponse([]);\n\t\t} catch (\\Exception $exception) {\n\t\t\t$this->logger->error('could not disable app', ['exception' => $exception]);\n\t\t\tthrow new OCSException('could not disable app', Http::STATUS_INTERNAL_SERVER_ERROR, $exception);\n\t\t}\n\t}\n\n\t/**\n\t * Uninstall an app.\n\t *\n\t * @param string $appId - The app to uninstall\n\t * @return DataResponse<Http::STATUS_OK, array{}, array{}>\n\t * @throws OCSException - if the app could not be uninstalled\n\t *\n\t * 200: App successfully uninstalled\n\t */\n\t#[PasswordConfirmationRequired(strict: true)]\n\t#[ApiRoute(verb: 'POST', url: '/api/v1/apps/uninstall')]\n\tpublic function uninstallApp(string $appId): DataResponse {\n\t\t$appId = $this->appManager->cleanAppId($appId);\n\t\tif ($this->appManager->isEnabledForAnyone($appId)) {\n\t\t\t$this->disableApp($appId);","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/nextcloud/server/blob/ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3/apps/appstore/lib/Controller/ApiController.php#L194-L230","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Only attempt disabling apps that are actually installed and disableable\nconst apps = (await axios.get(generateOcsUrl('/apps/appstore/apps/list'))).data\nconst target = apps.find((a) => a.id === appId)\nif (!target || !target.removableFromList) {\n\t// skip the call — it would 500\n}","typeGuard":null,"tryCatchPattern":"try {\n\tawait axios.post(generateOcsUrl('/apps/appstore/apps/disable'), { appId })\n} catch (e) {\n\t// 500 'could not disable app' — check nextcloud.log; verify appId validity and that the app may be disabled\n}","preventionTips":["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"],"tags":["appstore","apps","admin","php","ocs"],"backgroundTag":"app-disable-failed","analyzedSha":"ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3","analyzedAt":"2026-08-17T01:36:13.386Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}