matryer/xbar · warning

%s (from %s)

Error message

%s (from %s)

What it means

ParseFilenameInterval extracts the interval token from a plugin filename (the dotted segment before the extension) and parses it. If parseInterval fails, the library returns the default interval along with errors.Errorf("%s (from %s)") embedding the inner error and the full filename, so the developer can see which file had the malformed interval.

Source

Thrown at pkg/plugins/refresh_interval.go:122

		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
}

func findIntervalInFilename(filename string) string {
	if filename == "" {
		return ""
	}
	if !IsPluginEnabled(filename) {
		filename = strings.TrimSuffix(filename, disabledPluginExtension)
	}
	fn := filename
	ext := filepath.Ext(filename)
	if ext != "" {
		fn = fn[:len(fn)-len(ext)]
	}
	segs := strings.Split(fn, ".")
	if len(segs) == 1 {

View on GitHub (pinned to d624239058)

Solutions

  1. Rename the plugin file so its final dotted segment is a valid interval token: <name>.<N><d|h|m|s|ms>.<ext>, e.g. weather.5m.py
  2. If the plugin should just use the default interval, remove the dotted segment entirely (weather.py) — empty interval yields the default with no error
  3. Handle the returned defaultRefreshInterval when this error occurs, since the interval value is still usable (default 1 minute)

Example fix

// before
iv, err := plugins.ParseFilenameInterval("weather.5min.py") // bad interval value: 5mi...
// after
// rename file to a valid token first: weather.5m.py
iv, err := plugins.ParseFilenameInterval("weather.5m.py") // -> {5, minutes}
if err != nil {
    iv = plugins.RefreshInterval{N: 1, Unit: "minutes"} // accept default
}
Defensive patterns

Strategy: fallback

Validate before calling

var intervalRe = regexp.MustCompile(`\.\d+(ms|[dhms])\.[^.]+$`)
func filenameHasValidInterval(name string) bool {
    return intervalRe.MatchString(strings.TrimSuffix(name, ".stp"))
}

Try / catch

iv, err := plugins.ParseFilenameInterval(filename)
if err != nil {
    log.Printf("using default interval: %v", err)
    iv = plugins.RefreshInterval{N: 1, Unit: "minutes"} // default already returned; safe to ignore
}

Prevention

When it happens

Trigger: Calling plugins.ParseFilenameInterval (directly or via GetInstalledPluginMetadata/NewPlugin) on a filename whose last dotted segment is not a valid interval token, e.g. "weather.5x.py" or "notes..py" producing an empty/suffix parse failure; note filenames with NO interval segment return the default without error.

Common situations: Hand-renamed plugin files ("weather.5m.py" edited to "weather.5min.py"); plugin filenames where the final segment collides with interval parsing, like "my.tool.py" (parses unit 'l' -> bad unit); downloading a plugin renamed by a browser.

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