hashicorp/nomad · warning
Error querying CSI external volumes for plugin %q: %w
Error message
Error querying CSI external volumes for plugin %q: %w
What it means
When listing external (controller-managed) CSI volumes per plugin via client.CSIVolumes().ListExternal, any error other than io.EOF is appended to a multierror with this message. The loop then skips to the next plugin (NEXT_PLUGIN), so one bad plugin does not abort the whole listing.
Source
Thrown at command/volume_status_csi.go:101
return fmt.Errorf("Error querying CSI plugins: %w", err)
}
if len(plugins) == 0 {
return nil // No more output if we have no plugins
}
var mErr *multierror.Error
q := &api.QueryOptions{PerPage: 30} // TODO: tune page size
NEXT_PLUGIN:
for _, plugin := range plugins {
if !plugin.ControllerRequired || plugin.ControllersHealthy < 1 {
continue // only controller plugins can support this query
}
for {
externalList, _, err := client.CSIVolumes().ListExternal(plugin.ID, q)
if err != nil && !errors.Is(err, io.EOF) {
mErr = multierror.Append(mErr, fmt.Errorf(
"Error querying CSI external volumes for plugin %q: %w", plugin.ID, err))
// we'll stop querying this plugin, but there may be more to
// query, so report and set the error code but move on to the
// next plugin
continue NEXT_PLUGIN
}
if externalList == nil || len(externalList.Volumes) == 0 {
// several plugins return EOF once you hit the end of the page,
// rather than an empty list
continue NEXT_PLUGIN
}
c.Ui.Output("") // force a newline
rows := []string{"External ID|Condition|Nodes"}
for _, v := range externalList.Volumes {
condition := "OK"
if v.IsAbnormal {
condition = fmt.Sprintf("Abnormal (%v)", v.Status)
}View on GitHub (pinned to 482b49bf1a)
Solutions
- Inspect the wrapped error and plugin ID; deregister/redeploy the unhealthy CSI plugin (nomad plugin status, then fix the controller workload)
- Check the storage backend/controller reachability from the client node running the plugin
- Verify ACL token has volume listing permissions; re-run to see if other plugins listed fine
Example fix
// controller container crashing // before: plugin registered, ListExternal times out // after: fix controller deployment, then nomad plugin status <plugin-id> # ControllersHealthy >= 1 nomad volume status -verbose
Defensive patterns
Strategy: fallback
Validate before calling
for _, p := range plugins {
if p.ControllerRequired && p.ControllersHealthy < 1 {
// plugin will be skipped anyway; pre-warn users
}
} Type guard
func controllerCapable(p *api.CSIPluginListStub) bool { return p.ControllerRequired && p.ControllersHealthy >= 1 } Try / catch
if err := cmd.Run(); err != nil {
if strings.Contains(err.Error(), "Error querying CSI external volumes") {
// output may be partial: re-check plugin health before trusting results
}
} Prevention
- Monitor plugin ControllersHealthy; fix crash-looping controllers proactively
- Treat this error as partial-data, not total failure
- Deregister stale plugin instances (nomad system gc / plugin deregister)
When it happens
Trigger: csiVolumesList (verbose) iterates plugins where ControllerRequired is true and ControllersHealthy >= 1, and ListExternal(plugin.ID, q) returns a non-EOF error: controller RPC failure, plugin socket down, ACL denial, or timeout on the paginated query.
Common situations: A CSI plugin registers as healthy but its controller endpoint is broken (crash-looping controller pod), leaving stale registrations; also tokens lacking volume listing perms. Result is a partial listing plus an aggregated error at exit.
Related errors
- MaxEntries cannot be negative
- CSI.ControllerListSnapshots: %v
- Error querying CSI plugins: %w
- missing volume ID
- missing volume definition
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/a6e242412f5072ac.
Report an issue: GitHub.