matryer/xbar · warning

bad interval unit: %s

Error message

bad interval unit: %s

What it means

validateRefreshInterval checks Unit against the fixed list days, hours, minutes, seconds, milliseconds and returns errors.Errorf("bad interval unit: %s") for anything else. SetRefreshInterval wraps it as 'invalid refresh interval'. The library only supports these five units because they map to xbar filename interval suffixes (d/h/m/s/ms).

Source

Thrown at pkg/plugins/refresh_interval.go:108

	}
	newVarFilename := newFilename + variableJSONFileExt
	newVarFullPath := filepath.Join(pluginDirectory, newVarFilename)
	if err := os.Rename(oldVarFullPath, newVarFullPath); err != nil {
		return "", RefreshInterval{}, errors.Wrap(err, "rename plugin vars file to new refresh interval")
	}
	return newFilename, refreshInterval, nil
}

func validateRefreshInterval(refreshInterval RefreshInterval) error {
	if n := refreshInterval.N; n < 1 {
		return errors.Errorf("bad interval value: %d", n)
	}
	for _, unit := range []string{"days", "hours", "minutes", "seconds", "milliseconds"} {
		if refreshInterval.Unit == unit {
			return nil
		}
	}
	return errors.Errorf("bad interval unit: %s", refreshInterval.Unit)
}

// ParseFilenameInterval parses the filename to extract the refresh interval
// or returns a default if it is do so.
func ParseFilenameInterval(filename string) (RefreshInterval, error) {
	// ignore disabled piece
	filename = strings.TrimSuffix(filename, disabledPluginExtension)
	intervalStr := findIntervalInFilename(filename)
	if intervalStr == "" {
		return defaultRefreshInterval, nil
	}
	interval, err := parseInterval(intervalStr)
	if err != nil {
		return defaultRefreshInterval, errors.Errorf("%s (from %s)", err.Error(), filename)
	}
	return interval, nil
}

View on GitHub (pinned to d624239058)

Solutions

  1. Use exactly one of "days", "hours", "minutes", "seconds", "milliseconds" for Unit
  2. Normalize/sanitize user input (lowercase, map synonyms like "week" -> {N:7, Unit:"days"}) before constructing RefreshInterval
  3. Pre-construct intervals only from known constants rather than raw strings

Example fix

// before
_, _, err := plugins.SetRefreshInterval(dir, path, plugins.RefreshInterval{N: 1, Unit: "Week"})
// after
unit := strings.ToLower(unitInput)
if unit == "week" {
    unit = "days"
    n *= 7
}
_, _, err = plugins.SetRefreshInterval(dir, path, plugins.RefreshInterval{N: n, Unit: unit})
Defensive patterns

Strategy: validation

Validate before calling

var validUnits = map[string]bool{
    "days": true, "hours": true, "minutes": true,
    "seconds": true, "milliseconds": true,
}
func validUnit(u string) bool { return validUnits[strings.ToLower(u)] }

Try / catch

if !validUnit(iv.Unit) {
    return fmt.Errorf("unit %q not supported; use days|hours|minutes|seconds|milliseconds", iv.Unit)
}
_, _, err := plugins.SetRefreshInterval(dir, path, iv)

Prevention

When it happens

Trigger: Calling plugins.SetRefreshInterval with RefreshInterval{Unit: "week"}, "Minutes", "", or any casing/typo outside the exact five lowercase unit strings.

Common situations: Hand-written config using "weeks" or "days" with wrong casing; JSON deserialization of a user-supplied unit; translating a Go time.Duration string ("5m0s") into Unit; a UI locale differences.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of matryer/xbar@d624239058 (2026-09-02). Data as JSON: /api/errors/05d86a2c97729d7d. Report an issue: GitHub.