OpenHands/OpenHands · error · Error
Installing plugins is only available on a local backend.
Error message
Installing plugins is only available on a local backend.
What it means
Thrown by PluginsManagementService.installPlugin() when the active backend is cloud. Plugin installation writes to the agent-server's local filesystem (cloning a git repo or copying a local path into the plugins directory), which only exists on a local agent-server. The guard is a hard block — there is no cloud fallback path for plugin installation.
Source
Thrown at src/api/plugins-management-service.ts:96
if (isCloudBackend()) {
return [];
}
try {
const response = await getManagementClient().listInstalledPlugins();
return response.plugins ?? [];
} catch {
// Agent-server may predate the plugins router or be unreachable; surface
// an empty list rather than throwing (mirrors the catalog service).
return [];
}
}
static async installPlugin(
request: InstallPluginRequest,
): Promise<InstalledPluginInfo> {
if (isCloudBackend()) {
throw new Error(
"Installing plugins is only available on a local backend.",
);
}
return getManagementClient().installPlugin(request);
}
static async setPluginEnabled(
name: string,
enabled: boolean,
): Promise<{ name: string; enabled: boolean }> {
if (isCloudBackend()) {
throw new Error(
"Enabling and disabling plugins is only available on a local backend.",
);
}
return getManagementClient().setPluginEnabled(name, enabled);
}
View on GitHub (pinned to 500b4c533e)
Solutions
- Switch to a local backend before installing plugins (the Plugins page should gate the install action on backend kind === 'local').
- If the UI is not gating the button, ensure the component reads getActiveBackend() or useActiveBackendKind() and disables/hides the install action for cloud.
- Do not attempt to install plugins through a cloud runtime sandbox — plugin installation is not supported there.
Example fix
// Gate the install button on local backend
const { backend } = getActiveBackend();
<Button isDisabled={backend.kind !== 'local'} onClick={install}>
Install
</Button> Defensive patterns
Strategy: validation
Validate before calling
// Guard before calling installPlugin
import { getActiveBackend } from '#/api/backend-registry/active-store';
function canManagePlugins(): boolean {
return getActiveBackend().backend.kind === 'local';
}
if (!canManagePlugins()) {
toast.error('Switch to a local backend to install plugins.');
return;
} Type guard
function isLocalActiveBackend(): boolean {
return getActiveBackend().backend.kind === 'local';
} Try / catch
try {
await PluginsManagementService.installPlugin(request);
} catch (error) {
if (error instanceof Error && error.message.includes('only available on a local backend')) {
showBackendSwitchPrompt();
} else {
throw error;
}
} Prevention
- Gate all plugin management UI buttons on getActiveBackend().backend.kind === 'local'.
- Disable the Plugins management actions in the UI when a cloud backend is active.
- If plugin support for cloud is needed in the future, add a server-side management path rather than calling the local-only client.
When it happens
Trigger: Any call to PluginsManagementService.installPlugin(request) while getActiveBackend().backend.kind === 'cloud'. This typically happens when the UI does not gate the 'Install' button behind a local-backend check, or when a user switches to a cloud backend mid-session and then tries to install a plugin from the Plugins page.
Common situations: The user is connected to a Cloud backend and navigates to the Plugins page, then clicks Install. Or a stale React component calls the mutation without re-checking the active backend kind after a backend switch.
Related errors
- Enabling and disabling plugins is only available on a local
- Uninstalling plugins is only available on a local backend.
- Refreshing plugins is only available on a local backend.
- Reading plugin files is only available on a local backend.
- OAuth authorization requires a reachable local backend.
AI-assisted analysis of OpenHands/OpenHands@500b4c533e (2026-08-12).
Data as JSON: /api/errors/7f53827fbeb0ea63.
Report an issue: GitHub.