paperclipai/paperclip · error
Plugin UI is not available (status: ${plugin.status})
Error message
Plugin UI is not available (status: ${plugin.status}) What it means
Returned as HTTP 403 by the plugin UI static route (GET /_plugins/:pluginId/ui/*, server/src/routes/plugin-ui-static.ts:271). The route resolves the plugin by UUID or key, but only serves its UI bundle when the registry status is exactly 'ready'. Any other status ('installed', 'disabled', 'error', 'upgrade_pending', 'uninstalled') means the bundle on disk is not guaranteed complete, so serving is refused.
Source
Thrown at server/src/routes/plugin-ui-static.ts:271
? (error as { code?: unknown }).code
: undefined;
if (maybeCode !== "22P02") {
throw error;
}
}
if (!plugin) {
plugin = await registry.getByKey(pluginId);
}
if (!plugin) {
res.status(404).json({ error: "Plugin not found" });
return;
}
// Step 2: Verify the plugin is ready and has UI declared
if (plugin.status !== "ready") {
res.status(403).json({
error: `Plugin UI is not available (status: ${plugin.status})`,
});
return;
}
const manifest = plugin.manifestJson;
if (!manifest?.entrypoints?.ui) {
res.status(404).json({ error: "Plugin does not declare a UI bundle" });
return;
}
const rawCompanyId = req.query.companyId;
if (
Array.isArray(rawCompanyId) ||
(rawCompanyId !== undefined && typeof rawCompanyId !== "string")
) {
throw badRequest('"companyId" must be a string when provided');
}
const companyId = typeof rawCompanyId === "string" ? rawCompanyId.trim() : "";View on GitHub (pinned to 120ae5428f)
Solutions
- Check current status with GET /api/plugins (or GET /api/plugins?status=ready) and only load UI assets once the plugin reports 'ready'
- If status is 'error', inspect the install logs and re-run the install/repair flow to move it back to 'ready'
- If status is 'disabled' or 'uninstalled', re-enable or reinstall the plugin via the plugins API before loading its UI
- In host UI code, gate the dynamic import of the plugin UI entry on plugin.status === 'ready', and on a 403 re-fetch the plugin record instead of blindly retrying the asset URL
Example fix
// before
const mod = await import(`/_plugins/${pluginId}/ui/${entry}`);
// after
const plugin = await api.getPlugin(pluginId);
if (plugin.status !== "ready") {
throw new Error(`Plugin ${pluginId} not ready (status: ${plugin.status})`);
}
const mod = await import(`/_plugins/${pluginId}/ui/${entry}`); Defensive patterns
Strategy: validation
Validate before calling
const res = await fetch(`/api/plugins/${encodeURIComponent(pluginId)}`);
const plugin = await res.json();
if (plugin.status !== "ready") {
// Defer loading UI assets until the plugin is ready
throw new Error(`Plugin not ready: ${plugin.status}`);
} Type guard
const isPluginReady = (
p: { status: string },
): p is { status: "ready" } => p.status === "ready"; Try / catch
const assetRes = await fetch(url);
if (assetRes.status === 403) {
const { error } = await assetRes.json();
if (error.startsWith("Plugin UI is not available")) {
// Re-fetch plugin status and back off instead of retrying the asset
}
} Prevention
- Poll GET /api/plugins until status is 'ready' before importing the plugin UI bundle
- Gate extension-slot mounting on plugin.status === 'ready' AND a declared entrypoints.ui
- On 403 from /_plugins/:id/ui/*, invalidate cached plugin state and re-fetch rather than retrying the same URL
When it happens
Trigger: Requesting GET /_plugins/<pluginId>/ui/index.js (or any asset) while GET /api/plugins shows the plugin in a non-ready state: install still in flight ('installed'), install/build failed ('error'), mid-upgrade ('upgrade_pending'), disabled, or uninstalled. Typical when the UI tries to dynamically import the plugin bundle immediately after an install API call returns, before the registry flips the row to 'ready'.
Common situations: Polling a freshly installed plugin's UI too early; plugin card still rendered in the board after the plugin was disabled or uninstalled; an upgrade left the plugin in 'upgrade_pending'; install failed (status 'error') but a stale browser tab keeps requesting its assets.
Related errors
- File not found
- Access denied
- Plugin does not declare a UI bundle
- Plugin UI directory not found
- Failed to serve file
AI-assisted analysis of paperclipai/paperclip@120ae5428f (2026-08-18).
Data as JSON: /api/errors/614e8614ccbb8cff.
Report an issue: GitHub.