matryer/xbar · warning

bad interval value: %d

Error message

bad interval value: %d

What it means

validateRefreshInterval rejects a RefreshInterval whose N is less than 1 with errors.Errorf("bad interval value: %d"). SetRefreshInterval calls this before touching the filesystem and wraps it as 'invalid refresh interval'. The library requires a positive interval count because zero/negative durations make no scheduling sense.

Source

Thrown at pkg/plugins/refresh_interval.go:101

	_, err = os.Stat(oldVarFullPath)
	if err != nil && !os.IsNotExist(err) {
		return "", RefreshInterval{}, errors.Wrap(err, "stat plugin vars file")
	}
	if err != nil && os.IsNotExist(err) {
		// no variable file, no probs
		return newFilename, refreshInterval, nil
	}
	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
	}

View on GitHub (pinned to d624239058)

Solutions

  1. Pass N >= 1 with a valid Unit (days/hours/minutes/seconds/milliseconds) to SetRefreshInterval
  2. Validate the parsed JSON/config before constructing RefreshInterval, rejecting N < 1 at the boundary
  3. Coerce sub-1 values to the smallest allowed representation (e.g. 500ms as {N:500, Unit:"milliseconds"}) instead of {N:0.5, Unit:"seconds"}

Example fix

// before
iv, _ := strconv.ParseInt(userInput, 10, 64)
err := plugins.SetRefreshInterval(dir, path, plugins.RefreshInterval{N: iv, Unit: "minutes"}) // 0 -> error
// after
iv, err := strconv.ParseInt(userInput, 10, 64)
if err != nil || iv < 1 {
    iv = 1
}
_, _, err = plugins.SetRefreshInterval(dir, path, plugins.RefreshInterval{N: iv, Unit: "minutes"})
Defensive patterns

Strategy: validation

Validate before calling

func validInterval(iv plugins.RefreshInterval) bool {
    return iv.N >= 1
}
// call: if !validInterval(iv) { iv = plugins.RefreshInterval{N: 1, Unit: "minutes"} }

Try / catch

if _, _, err := plugins.SetRefreshInterval(dir, path, iv); err != nil {
    if strings.Contains(err.Error(), "bad interval value") {
        _, _, err = plugins.SetRefreshInterval(dir, path, plugins.RefreshInterval{N: 1, Unit: "minutes"})
    }
}

Prevention

When it happens

Trigger: Calling plugins.SetRefreshInterval (or validateRefreshInterval in tests) with plugins.RefreshInterval{N: 0, ...} or {N: -5, ...}. Note the check is n < 1, so N must be >= 1.

Common situations: Unmarshaling an interval from JSON where the field is missing (N defaults to 0); a UI sending an empty/zero value; user typing 0 in a settings field; integer overflow or truncation from a float seconds value of 0.5.

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/bbdce4e2dbe28f21. Report an issue: GitHub.