spicetify/cli · critical
panic(err)
Error message
panic(err)
What it means
getDefaultConfig builds the default INI config with go-ini, iterating over configLayout and creating a section per name via cfg.NewSection. If NewSection returns an error the code panics instead of returning an error. With go-ini, NewSection errors when a section with that name already exists, so this panic fires during ParseConfig's default-config creation if a section name is duplicated.
Source
Thrown at src/utils/config.go:150
spotifyPath := FindAppPath()
prefsFilePath := FindPrefFilePath()
if len(spotifyPath) == 0 {
PrintError("Could not detect Spotify location")
} else {
configLayout["Setting"]["spotify_path"] = spotifyPath
}
if len(prefsFilePath) == 0 {
PrintError("Could not detect \"prefs\" file location")
} else {
configLayout["Setting"]["prefs_path"] = prefsFilePath
}
for sectionName, keyList := range configLayout {
section, err := cfg.NewSection(sectionName)
if err != nil {
panic(err)
}
for keyName, defaultValue := range keyList {
section.NewKey(keyName, defaultValue)
}
}
version, err := cfg.NewSection("Backup")
if err != nil {
panic(err)
}
version.Comment = "DO NOT CHANGE!"
version.NewKey("version", "")
version.NewKey("with", "")
return cfg
}
// FindAppPath finds Spotify location in various possible places
// of each platform and returns it.View on GitHub (pinned to 1f13f73616)
Solutions
- Check configLayout for duplicate section names (including hidden duplicates like "Setting" vs " Setting") and remove them.
- Ensure no section name in configLayout is an empty string; give every section a valid non-empty name.
- If you control the code, replace panic(err) with returning the error up through ParseConfig so callers can handle it.
- Delete any partially written config file and retry, in case a stale/partial default file is implicated.
Example fix
// before
section, err := cfg.NewSection(sectionName)
if err != nil {
panic(err)
}
// after
section, err := cfg.NewSection(sectionName)
if err != nil {
return nil, fmt.Errorf("creating section %q: %w", sectionName, err)
} Defensive patterns
Strategy: try-catch
Validate before calling
// Go: recover from the panic at the call site of ParseConfig
func safeParseConfig() (cfg interface{}, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("config init panicked: %v", r)
}
}()
return utils.ParseConfig(), nil
} Try / catch
defer func() {
if r := recover(); r != nil {
log.Errorf("getDefaultConfig panicked: %v — check configLayout for duplicate section names", r)
}
}() Prevention
- Keep one canonical entry per section in configLayout; add a startup test asserting unique section names.
- Reject empty section names in configLayout before iterating.
- Convert panics into returned errors in library code so callers can recover.
- Pin/patch the library version if a release shipped with a duplicate-section bug.
When it happens
Trigger: Running ParseConfig on a fresh install when configLayout contains a duplicate section name (two entries for the same section key), causing cfg.NewSection(sectionName) to return "section ... already exists" and the code to panic. Also triggered by any go-ini error from NewSection, e.g. an empty section name.
Common situations: A developer added a new key and accidentally created a second map entry for an existing section; configLayout was edited with an empty-string section name; library shipped with a mis-merged config layout map. End users hit it as an immediate crash on first run when the config file doesn't exist yet.
Related errors
- config "current_theme" is blank
- end marker not found after start index %d: %s
- error decoding UTF-16LE content: %w
- invalid UTF-16LE data length
AI-assisted analysis of spicetify/cli@1f13f73616 (2026-08-31).
Data as JSON: /api/errors/18d07eb89edcd450.
Report an issue: GitHub.