prometheus/node_exporter · error

csrow string didn't match regexp

Error message

csrow string didn't match regexp: %s

What it means

The EDAC collector globs /sys/devices/system/edac/mc/mc*/csrow* directories and parses each path with edacMemCsrowRE to extract the csrow number. When a matched path's basename does not match the expected regexp, Update returns this error and the whole collector scrape fails. It indicates an unexpected sysfs layout rather than bad user input.

Solutions

  1. Check `ls /sys/devices/system/edac/mc/mc*/` for entries that do not look like csrowN and identify the driver creating them.
  2. Unload or update the offending EDAC kernel module, or use a kernel whose EDAC layout matches the collector's regexp.
  3. Verify the collector version matches your kernel generation (newer kernels replaced csrow with dimm/* layout, handled by a different code path).
  4. If a legitimate new layout is found, file/patch upstream to extend edacMemCsrowRE.

Example fix

// before: regexp assumes only csrowN basenames
var edacMemCsrowRE = regexp.MustCompile(`csrow([0-9]*)`)

// after: skip-but-log unmatched entries instead of failing the scrape
if csrowMatch == nil {
	logger.Debug("skipping unmatched csrow entry", "path", csrow)
	continue
}
Defensive patterns

Strategy: validation

Validate before calling

const cmd = require('child_process').execSync;
const csrows = cmd("ls -d /sys/devices/system/edac/mc/mc*/csrow* 2>/dev/null || true").toString().trim();
if (csrows) {
  const bad = csrows.split('\n').filter(p => !/csrow\d+$/.test(p));
  if (bad.length) console.warn('Unrecognized EDAC entries, edac collector may fail:', bad);
}

Type guard

function isCsrowPath(p) { return /csrow\d+$/.test(p); }

Prevention

When it happens

Trigger: filepath.Glob returns a path (e.g. mc0/csrow0 or an unexpected file) whose basename fails to match edacMemCsrowRE during Collector.Update.

Common situations: Custom or non-standard EDAC kernel drivers exposing unusual entries under the mc/ directory; kernel versions with different csrow layout; leftover entries created by loaded-but-broken EDAC modules; test fixtures with malformed csrow names.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at collector/edac_linux.go:148

		ch <- prometheus.MustNewConstMetric(
			edacUeCount, prometheus.CounterValue, float64(value), controllerNumber)

		value, err = readUintFromFile(filepath.Join(controller, "ue_noinfo_count"))
		if err != nil {
			return fmt.Errorf("couldn't get ue_noinfo_count for controller %s: %w", controllerNumber, err)
		}
		ch <- prometheus.MustNewConstMetric(
			edacCsRowUECount, prometheus.CounterValue, float64(value), controllerNumber, "unknown")

		// For each controller, walk the csrow directories.
		csrows, err := filepath.Glob(controller + "/csrow[0-9]*")
		if err != nil {
			return err
		}
		for _, csrow := range csrows {
			csrowMatch := edacMemCsrowRE.FindStringSubmatch(csrow)
			if csrowMatch == nil {
				return fmt.Errorf("csrow string didn't match regexp: %s", csrow)
			}
			csrowNumber := csrowMatch[1]

			value, err = readUintFromFile(filepath.Join(csrow, "ce_count"))
			if err != nil {
				return fmt.Errorf("couldn't get ce_count for controller/csrow %s/%s: %w", controllerNumber, csrowNumber, err)
			}
			ch <- prometheus.MustNewConstMetric(
				edacCsRowCECount, prometheus.CounterValue, float64(value), controllerNumber, csrowNumber)

			value, err = readUintFromFile(filepath.Join(csrow, "ue_count"))
			if err != nil {
				return fmt.Errorf("couldn't get ue_count for controller/csrow %s/%s: %w", controllerNumber, csrowNumber, err)
			}
			ch <- prometheus.MustNewConstMetric(
				edacCsRowUECount, prometheus.CounterValue, float64(value), controllerNumber, csrowNumber)

			channelFiles, err := filepath.Glob(csrow + "/ch*_ce_count")

View on GitHub (pinned to 17ddd77c59)