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

  1. Check configLayout for duplicate section names (including hidden duplicates like "Setting" vs " Setting") and remove them.
  2. Ensure no section name in configLayout is an empty string; give every section a valid non-empty name.
  3. If you control the code, replace panic(err) with returning the error up through ParseConfig so callers can handle it.
  4. 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

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


AI-assisted analysis of spicetify/cli@1f13f73616 (2026-08-31). Data as JSON: /api/errors/18d07eb89edcd450. Report an issue: GitHub.