matryer/xbar · error

invalid refresh interval

Error message

invalid refresh interval

What it means

SetRefreshInterval renames a plugin file to embed a new refresh interval and validates the requested interval first. This error wraps validateRefreshInterval's rejection — the supplied RefreshInterval is not one of the supported values, so no rename is performed.

Source

Thrown at pkg/plugins/refresh_interval.go:70

		return fmt.Sprintf("%dd", r.N)
	case "hours":
		return fmt.Sprintf("%dh", r.N)
	case "minutes":
		return fmt.Sprintf("%dm", r.N)
	case "seconds":
		return fmt.Sprintf("%ds", r.N)
	case "milliseconds":
		return fmt.Sprintf("%dms", r.N)
	default:
		return "<invalid>"
	}
}

// SetRefreshInterval sets the time interval at which a plugin should be re-run.
func SetRefreshInterval(pluginDirectory, installedPluginPath string, refreshInterval RefreshInterval) (string, RefreshInterval, error) {
	interval := findIntervalInFilename(installedPluginPath)
	if err := validateRefreshInterval(refreshInterval); err != nil {
		return "", RefreshInterval{}, errors.Wrap(err, "invalid refresh interval")
	}
	oldFullPath := filepath.Join(pluginDirectory, installedPluginPath)
	newFilename := strings.Replace(installedPluginPath, "."+interval+".", "."+refreshInterval.String()+".", 1)
	newFullPath := filepath.Join(pluginDirectory, newFilename)
	if err := os.Rename(oldFullPath, newFullPath); err != nil {
		return "", RefreshInterval{}, errors.Wrap(err, "rename plugin file to new refresh interval")
	}
	_, err := os.Stat(newFullPath)
	if err != nil {
		return "", RefreshInterval{}, errors.Wrap(err, "stat plugin file")
	}
	oldVarFullPath := oldFullPath + variableJSONFileExt
	_, 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

View on GitHub (pinned to d624239058)

Solutions

  1. Use one of the library's predefined RefreshInterval constants rather than constructing one manually
  2. Check the wrapped error (errors.Cause) to see exactly what validation rejected
  3. If storing intervals externally, re-normalize them against the current library's supported set
  4. Verify the plugin's installed filename actually contains an interval segment (e.g. name.5m.sh) via findIntervalInFilename

Example fix

// before
interval := RefreshInterval{Seconds: 45}          // unsupported value
SetRefreshInterval(dir, path, interval)
// after
interval := RefreshInterval5m                      // predefined constant
SetRefreshInterval(dir, path, interval)
Defensive patterns

Strategy: validation

Validate before calling

switch refreshInterval.String() {
case "1m", "5m", "10m", "15m", "30m", "1h": // supported set per library docs
default:
    return fmt.Errorf("unsupported refresh interval %q", refreshInterval.String())
}

Try / catch

newPath, _, err := plugins.SetRefreshInterval(dir, path, interval)
if err != nil {
    var verr error
    if errors.As(err, &verr) && errors.Unwrap(err) != nil {
        log.Printf("interval rejected: %v", errors.Unwrap(err))
    }
    interval = plugins.RefreshInterval5m // fall back to a known-good interval
}

Prevention

When it happens

Trigger: Calling SetRefreshInterval(pluginDirectory, installedPluginPath, refreshInterval) with a refreshInterval that fails validateRefreshInterval — e.g. zero-value RefreshInterval{}, a hand-built struct with an unrecognized seconds value, or one not matching the fixed set of intervals.

Common situations: External tools constructing a RefreshInterval manually instead of using the library's predefined constants; UI storing an interval that changed between library versions; config files with stale/unsupported interval numbers.

Related errors


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