cloudflare/cloudflared · error

expected disk volume to have %d fields got %d: %w

Error message

expected disk volume to have %d fields got %d: %w

What it means

ParseDiskVolumeInformationOutput validates that each line of `df`-style disk volume output contains at least `diskFieldsMinimum` whitespace-separated fields. When a line is too sparse it returns ErrInsuficientFields wrapped in this message, since fields like device name and mount point cannot be extracted reliably from a malformed line.

Source

Thrown at diagnostic/system_collector_utils.go:87

		sizeCurrentField  = 2
	)

	disksRaw := strings.Split(output, "\n")
	disks := make([]*DiskVolumeInformation, 0)

	if skipLines > len(disksRaw) || skipLines < 0 {
		skipLines = 0
	}

	for _, disk := range disksRaw[skipLines:] {
		if disk == "" {
			// skip empty line
			continue
		}

		fields := strings.Fields(disk)
		if len(fields) < diskFieldsMinimum {
			return nil, fmt.Errorf("expected disk volume to have %d fields got %d: %w",
				diskFieldsMinimum, len(fields), ErrInsuficientFields,
			)
		}

		name := fields[nameField]

		sizeMaximum, err := strconv.ParseUint(fields[sizeMaximumField], 10, 64)
		if err != nil {
			continue
		}

		sizeCurrent, err := strconv.ParseUint(fields[sizeCurrentField], 10, 64)
		if err != nil {
			continue
		}

		diskInfo := NewDiskVolumeInformation(
			name, uint64(float64(sizeMaximum)*scale), uint64(float64(sizeCurrent)*scale),

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Strip the df header line before parsing (skip the first line or filter lines starting with 'Filesystem').
  2. Call df with portable flags (e.g. `df -P -k`) so every data line has the standard 6 columns.
  3. Check the df output on the failing host for line wrapping — use longer device-name output or `-P` to prevent wraps.
  4. Set LC_ALL=C when invoking df to avoid locale-dependent column variations.

Example fix

// before
out, _ := exec.Command("df").Output()
info, err := diagnostic.ParseDiskVolumeInformationOutput(string(out))
// after
out, _ := exec.Command("df", "-P", "-k").Output()
lines := strings.Split(string(out), "\n")
if len(lines) > 0 {
	lines = lines[1:] // drop header
}
info, err := diagnostic.ParseDiskVolumeInformationOutput(strings.Join(lines, "\n"))
Defensive patterns

Strategy: validation

Validate before calling

func validateDiskOutput(output string) error {
	for _, line := range strings.Split(output, "\n") {
		line = strings.TrimSpace(line)
		if line == "" || strings.HasPrefix(line, "Filesystem") {
			continue
		}
		if len(strings.Fields(line)) < 6 {
			return fmt.Errorf("disk line too short: %q", line)
		}
	}
	return nil
}

Try / catch

info, err := diagnostic.ParseDiskVolumeInformationOutput(dfOutput)
var target error = diagnostic.ErrInsuficientFields
if errors.Is(err, target) {
	log.Warn().Msg("skipping malformed disk volume line")
} else if err != nil {
	return fmt.Errorf("disk parse failed: %w", err)
}

Prevention

When it happens

Trigger: Calling ParseDiskVolumeInformationOutput (directly or via collectDiskVolumeInformationUnix/collectDiskVolumeInformation during Collect) with df output whose header line or a truncated line has fewer fields than diskFieldsMinimum — e.g. parsing df output that still includes the 'Filesystem ... Mount on' header, or a locale producing extra/short lines.

Common situations: Forgetting `df -P` style normalization so wrapped device names split across lines, localized df headers/columns on non-English systems, empty or partial output when the disk is unavailable, or feeding the function raw output that includes blank or banner lines.

Related errors


AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06). Data as JSON: /api/errors/0ab5e4d70fe35561. Report an issue: GitHub.