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
- 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
- If the plugin should just use the default interval, remove the dotted segment entirely (weather.py) — empty interval yields the default with no error
- 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
- Treat the returned default interval as valid even when err != nil
- Sanitize plugin filenames at install time to enforce <name>.<N><unit>.<ext>
- Avoid dots inside plugin base names (use hyphens instead)
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
- bad interval value: %s
- not an xbar:// url
- unsupported action %q
- malformed xbar.var format
- malformed xbar.var format (missing select options)
AI-assisted analysis of matryer/xbar@d624239058 (2026-09-02).
Data as JSON: /api/errors/c651dd8b3b376a61.
Report an issue: GitHub.