prometheus/node_exporter · error

--collector.qdisk.device-exclude and…

Error message

--collector.qdisk.device-exclude and --collector.qdisc.device-exclude are mutually exclusive

What it means

NewQdiscStatCollector refuses to start when both the deprecated --collector.qdisk.device-exclude flag and the current --collector.qdisc.device-exclude flag are set. The deprecated qdisk spelling only auto-migrates when the new qdisc flag is empty; setting both is ambiguous and rejected.

Solutions

  1. Remove the deprecated --collector.qdisk.device-exclude flag and keep only --collector.qdisc.device-exclude
  2. Search deployment configs for 'qdisk' and replace with 'qdisc'
  3. Restart node_exporter

Example fix

// before
node_exporter --collector.qdisk.device-exclude=lo --collector.qdisc.device-exclude=docker0
// after
node_exporter --collector.qdisc.device-exclude=docker0
Defensive patterns

Strategy: validation

Validate before calling

func validateQdiscExcludeFlags(oldExclude, newExclude string) error {
	if oldExclude != "" && newExclude != "" {
		return fmt.Errorf("set only one of --collector.qdisk.device-exclude (deprecated) or --collector.qdisc.device-exclude")
	}
	return nil
}

Try / catch

c, err := NewQdiscStatCollector(logger)
if err != nil {
	logger.Error("qdisc collector disabled", "err", err)
}

Prevention

When it happens

Trigger: Starting node_exporter with both --collector.qdisk.device-exclude=<v> and --collector.qdisc.device-exclude=<v> non-empty; the constructor returns this error immediately.

Common situations: Leftover old flag in a systemd unit or config-management manifest after the new flag was added; duplicated args accumulated from two config layers.

Understand the failure class

Background: "mutually exclusive" flag errors: what "can't supply both nx and xx", "--raw is not compatible with -i" and "cannot be used with" mean, and how to fix them — this error's family across 29 libraries.

Related errors


AI-assisted analysis of prometheus/node_exporter@17ddd77c59 (2026-09-07). Data as JSON: /api/errors/001b015143c98431. Report an issue: GitHub.

Appendix: source

Thrown at collector/qdisc_linux.go:70

}

// NewQdiscStatCollector returns a new Collector exposing queuing discipline statistics.
func NewQdiscStatCollector(logger *slog.Logger) (Collector, error) {
	if *oldCollectorQdiskDeviceInclude != "" {
		if *collectorQdiscDeviceInclude == "" {
			logger.Warn("--collector.qdisk.device-include is DEPRECATED and will be removed in 2.0.0, use --collector.qdisc.device-include")
			*collectorQdiscDeviceInclude = *oldCollectorQdiskDeviceInclude
		} else {
			return nil, fmt.Errorf("--collector.qdisk.device-include and --collector.qdisc.device-include are mutually exclusive")
		}
	}

	if *oldCollectorQdiskDeviceExclude != "" {
		if *collectorQdiscDeviceExclude == "" {
			logger.Warn("--collector.qdisk.device-exclude is DEPRECATED and will be removed in 2.0.0, use --collector.qdisc.device-exclude")
			*collectorQdiscDeviceExclude = *oldCollectorQdiskDeviceExclude
		} else {
			return nil, fmt.Errorf("--collector.qdisk.device-exclude and --collector.qdisc.device-exclude are mutually exclusive")
		}
	}

	if *collectorQdiscDeviceExclude != "" && *collectorQdiscDeviceInclude != "" {
		return nil, fmt.Errorf("collector.qdisc.device-include and collector.qdisc.device-exclude are mutaly exclusive")
	}

	return &qdiscStatCollector{
		bytes: typedDesc{prometheus.NewDesc(
			prometheus.BuildFQName(namespace, "qdisc", "bytes_total"),
			"Number of bytes sent.",
			[]string{"device", "kind"}, nil,
		), prometheus.CounterValue},
		packets: typedDesc{prometheus.NewDesc(
			prometheus.BuildFQName(namespace, "qdisc", "packets_total"),
			"Number of packets sent.",
			[]string{"device", "kind"}, nil,
		), prometheus.CounterValue},

View on GitHub (pinned to 17ddd77c59)