{"record":{"id":"82eb82b15697c637","repo":"alibaba/nacos","slug":"plugin-selection-for-exclusive-type-requires","errorCode":null,"errorMessage":"Plugin selection for exclusive type '{}' requires restart. Update '{}' instead.","messagePattern":"Plugin selection for exclusive type '(.+?)' requires restart\\. Update '(.+?)' instead\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"warning","filePath":"core/src/main/java/com/alibaba/nacos/core/plugin/PluginManager.java","lineNumber":773,"sourceCode":"        refreshAllCriticalFlags();\n    }\n    \n    private void validateStateChangeInternal(PluginInfo info, boolean enabled) {\n        validateRuntimeChangeSupported(info, \"state\");\n        if (info.isEnabled() == enabled) {\n            return;\n        }\n        PluginType type = info.getPluginType();\n        if (type.isCritical() && policyRegistry.isActive(type)) {\n            Map<String, Boolean> targetStates = getCurrentStates();\n            targetStates.put(info.getPluginId(), enabled);\n            String validationError = getCriticalValidationError(type, targetStates);\n            if (validationError != null) {\n                throw new IllegalArgumentException(validationError);\n            }\n        }\n        if (type.isExclusive()) {\n            throw new IllegalArgumentException(\"Plugin selection for exclusive type '\"\n                + type.getType() + \"' requires restart. Update '\" + getSelectionProperty(type)\n                + \"' instead.\");\n        }\n    }\n    \n    private long countEnabledPlugins(PluginType type) {\n        return pluginRegistry.values().stream()\n            .filter(info -> type == info.getPluginType() && info.isEnabled()).count();\n    }\n    \n    private void validateCriticalStates(Map<String, Boolean> targetStates) {\n        for (PluginType type : PluginType.values()) {\n            String validationError = getCriticalValidationError(type, targetStates);\n            if (validationError != null) {\n                LOGGER.error(\"[PluginManager] {}\", validationError);\n                throw new IllegalStateException(validationError);\n            }\n        }","sourceCodeStart":755,"sourceCodeEnd":791,"githubUrl":"https://github.com/alibaba/nacos/blob/9b989acdf181d00898f2e8839257bb2b2a3cefe3/core/src/main/java/com/alibaba/nacos/core/plugin/PluginManager.java#L755-L791","documentation":"validateStateChangeInternal throws IllegalArgumentException (mapped by setPluginEnabled to NacosApiException HTTP 400 / PARAMETER_VALIDATE_ERROR 20002) when toggling a plugin whose PluginType.isExclusive() is true. Exclusive types allow only one active plugin, selected at startup via a selection property — they cannot be switched at runtime. Exposed via PUT /v3/console/plugin/status.","triggerScenarios":"PUT /v3/console/plugin/status enabling a different plugin of an exclusive type (e.g. enabling auth:ldap when auth:nacos is already the selected auth plugin), or toggling any exclusive-type plugin.","commonSituations":"Trying to switch the active auth / datasource-dialect / similar exclusive plugin through the runtime enable API instead of configuration; not knowing a type is exclusive.","solutions":["Do not use the runtime toggle for exclusive plugin types.","Set the selection property named in the error (e.g. nacos.core.auth.plugin.type / the type's selector) in application.properties and restart the server.","Use GET /v3/console/plugin to inspect which type a plugin belongs to and whether it is exclusive."],"exampleFix":"// before\nPUT /v3/console/plugin/status?pluginType=auth&pluginName=ldap&enabled=true\n// after: set selection property and restart\n# application.properties\nnacos.core.auth.plugin.type=ldap","handlingStrategy":"validation","validationCode":"PluginDetailVO detail = pluginClient.getDetail(pluginType, pluginName);\nif (detail.getPluginType().isExclusive()) {\n    throw new IllegalStateException(\"exclusive type \" + pluginType\n        + \" cannot be toggled at runtime; set its selection property and restart\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    pluginClient.setEnabled(type, name, enabled, localOnly);\n} catch (NacosApiException e) {\n    if (e.getErrCode() == 20002 && e.getMessage().contains(\"exclusive type\")) {\n        // route the user to set the selection property + restart instead\n    } else { throw e; }\n}","preventionTips":["Never toggle exclusive plugin types (auth/datasource dialect) at runtime.","Switch exclusive plugins via their selection property + restart.","Check the plugin type metadata for isExclusive before enabling."],"tags":["plugin","exclusive","restart-required","validation"],"backgroundTag":null,"analyzedSha":"9b989acdf181d00898f2e8839257bb2b2a3cefe3","analyzedAt":"2026-08-14T07:17:31.569Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}