wtfutil/wtf · critical

panic(err)

Error message

panic(err)

What it means

migrateOldConfig moves an old config directory to the new location with Copy and unconditionally panics if the copy fails. This is an intentional fail-fast during app startup (Initialize path): the developers decided that a half-migrated config is unrecoverable, so a panic with the raw error is raised instead of returning an error.

Source

Thrown at cfg/config_files.go:220

// to the new, XDG-compatible location
func migrateOldConfig() {
	srcDir, _ := expandHomeDir(WtfConfigDirV1)
	destDir, _ := WtfConfigDir()

	// If the old config directory doesn't exist, do not move
	if _, err := os.Stat(srcDir); os.IsNotExist(err) {
		return
	}

	// If the new config directory already exists, do not move
	if _, err := os.Stat(destDir); err == nil {
		return
	}

	// Time to move
	err := Copy(srcDir, destDir)
	if err != nil {
		panic(err)
	}

	// Delete the old directory if the new one exists
	if _, err := os.Stat(destDir); err == nil {
		err := os.RemoveAll(srcDir)
		if err != nil {
			fmt.Println(err)
		}
	}
}

View on GitHub (pinned to bb838c1ccb)

Solutions

  1. Read the wrapped panic message to identify the OS-level cause (permission denied, no space, etc.) and fix that filesystem condition
  2. Manually copy the old config directory to the new location yourself, then restart so migration is skipped
  3. Check write permissions on the destination config directory for the user running the app
  4. Ensure sufficient disk space and that destDir is not a regular file

Example fix

// before
$ whoami # wrong user, no write access to ~/.config
# after
sudo chown -R $(whoami) ~/.config/myapp && restart app
Defensive patterns

Strategy: fallback

Validate before calling

// check migration preconditions before startup
if _, err := os.Stat(destDir); err == nil {
    // already migrated; skip
}
if err := unix.Access(filepath.Dir(destDir), unix.W_OK); err != nil {
    log.Fatalf("config dir not writable: %v", err)
}

Try / catch

// recover at startup so a failed migration doesn't kill the process
func safeInit() (ok bool) {
    defer func() {
        if r := recover(); r != nil {
            log.Printf("config migration failed: %v", r)
            ok = false
        }
    }()
    Initialize(cfgPath)
    return true
}

Prevention

When it happens

Trigger: Initialize detects an old config directory and calls Copy(srcDir, destDir); the copy fails due to permission errors (read-only destination), disk full, srcDir unreadable, or destDir existing as a file.

Common situations: Upgrading the app under a service account that lacks write permission to ~/.config; running in a container with a read-only filesystem or small disk; stale lock/permission issues after switching users.

Related errors


AI-assisted analysis of wtfutil/wtf@bb838c1ccb (2026-09-03). Data as JSON: /api/errors/649be5902327fbe2. Report an issue: GitHub.