rustfs/rustfs · error · TargetPluginExternalActionError
plugin {plugin_id} is not an external plugin
Error message
plugin {plugin_id} is not an external plugin What it means
TargetPluginExternalActionError::NotExternalPlugin is returned by validate_external_action_subject (crates/targets/src/control_plane.rs:424-432), the first check plan_external_target_plugin_action performs. The external planning flow only accepts marketplace manifests whose packaging field equals TargetPluginPackaging::External; builtin-packaged plugins (e.g. builtin:webhook) are managed through the builtin registration path instead.
Source
Thrown at crates/targets/src/control_plane.rs:261
pub struct TargetPluginExternalFlowGateStatus {
pub enabled: bool,
pub install_requires_signature: bool,
pub install_requires_provenance: bool,
pub runtime_allows_external_sidecars: bool,
pub runtime_requires_sandbox: bool,
pub runtime_requires_provenance: bool,
pub circuit_breaker_closed: bool,
pub max_queue_depth: usize,
pub failure_threshold: usize,
pub redacts_error_details: bool,
}
#[derive(Debug, Error, PartialEq, Eq)]
pub enum TargetPluginExternalActionError {
#[error("external plugin flow is disabled")]
ExternalFlowDisabled,
#[error("plugin {plugin_id} is not an external plugin")]
NotExternalPlugin { plugin_id: String },
#[error("plugin {plugin_id} is not installed")]
NotInstalled { plugin_id: String },
#[error("plugin {plugin_id} has no previous revision for rollback")]
MissingPreviousRevision { plugin_id: String },
#[error("external plugin install policy denied action: {reason}")]
InstallPolicyDenied { reason: String },
#[error("external plugin runtime policy denied action: {reason}")]
RuntimePolicyDenied { reason: String },
#[error("external plugin circuit breaker is open")]
CircuitBreakerOpen,
#[error("external plugin {plugin_id} has no installable artifact for host target triple {target_triple}")]View on GitHub (pinned to 35af688cd9)
Solutions
- Branch on manifest.packaging: use the builtin registry/installation path (builtin_target_plugin_installation) for builtin plugins and the external flow only for TargetPluginPackaging::External
- Use an external-packaged manifest such as example_external_webhook_plugin().manifest when exercising the external flow
- Set packaging = TargetPluginPackaging::External in the marketplace manifest if the plugin really ships as a downloadable sidecar artifact
Example fix
// before
let result = plan_external_target_plugin_action(
&builtin_target_marketplace_manifest("webhook"), // packaging: Builtin
TargetPluginExternalAction::Install, &inst, &gate, triple); // NotExternalPlugin
// after
if manifest.packaging == TargetPluginPackaging::External {
plan_external_target_plugin_action(&manifest, action, &inst, &gate, triple)?;
} else {
let installation = builtin_target_plugin_installation(&manifest); // builtin path
} Defensive patterns
Strategy: validation
Validate before calling
use crate::manifest::TargetPluginPackaging;
if manifest.packaging != TargetPluginPackaging::External {
// route to the builtin registration/installation path instead
let installation = builtin_target_plugin_installation(&builtin_manifest);
} Type guard
fn is_external_plugin(manifest: &TargetPluginMarketplaceManifest) -> bool {
manifest.packaging == TargetPluginPackaging::External
} Try / catch
match plan_external_target_plugin_action(&manifest, action, &inst, &gate, triple) {
Err(TargetPluginExternalActionError::NotExternalPlugin { plugin_id }) => /* use the builtin path for plugin_id */,
Ok(decision) => { /* apply */ }
Err(e) => return Err(e.into()),
} Prevention
- Branch on manifest.packaging before choosing the external or builtin flow
- In marketplace metadata, always set packaging explicitly
- Remember builtin plugin ids carry the 'builtin:' prefix - a quick smell test
When it happens
Trigger: Passing builtin_target_marketplace_manifest("webhook") or any manifest with packaging != External to plan_external_target_plugin_action, for any action (Install, Enable, Disable, Rollback).
Common situations: Admin handlers routing every plugin through the external flow; tests using builtin manifests as convenient fixtures; a manifest author forgetting packaging: external in marketplace metadata.
Related errors
- external plugin flow is disabled
- plugin {plugin_id} is not installed
- plugin {plugin_id} has no previous revision for rollback
- external plugin install policy denied action: {reason}
- external plugin runtime policy denied action: {reason}
AI-assisted analysis of rustfs/rustfs@35af688cd9 (2026-08-20).
Data as JSON: /api/errors/51e5d818f339df76.
Report an issue: GitHub.