kopia/kopia · error

invalid UI preferences file

Error message

invalid UI preferences file

What it means

Thrown by getUIPreferencesOrEmpty when the UI preferences file opens successfully but json.NewDecoder(f).Decode fails, meaning the file content is not valid JSON or does not decode into the expected preferences structure.

Solutions

  1. Validate the file with a JSON linter and fix syntax errors.
  2. Restore the file from backup or delete it (it will be recreated with empty preferences).
  3. Check the wrapped Decode error for the exact JSON offset of the problem.
  4. Ensure writes to the file are atomic (write temp file + rename) to avoid truncation.

Example fix

// before
{ "theme": "dark", }
// after: valid JSON
{ "theme": "dark" }
Defensive patterns

Strategy: fallback

Validate before calling

b, err := os.ReadFile(prefsFile)
if err == nil {
    var p map[string]any
    if err := json.Unmarshal(b, &p); err != nil { return fmt.Errorf("invalid prefs JSON: %w", err) }
}

Try / catch

prefs, err := client.GetUIPreferences(ctx)
if err != nil && strings.Contains(err.Error(), "invalid UI preferences file") {
    // repair or reset the file, then retry
    return resetPrefsFileAndRetry(ctx)
}

Prevention

When it happens

Trigger: GET UI preferences when UIPreferencesFile contains malformed JSON (truncated write, manual edit with syntax error, wrong file supplied).

Common situations: Hand-edited preferences file with a trailing comma or comments; file truncated by a crash or full disk; user pointed the option at a non-JSON file.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


AI-assisted analysis of kopia/kopia@82495e54b5 (2026-09-07). Data as JSON: /api/errors/2e4c8abe34fc5c6d. Report an issue: GitHub.

Appendix: source

Thrown at internal/server/api_ui_pref.go:34

	p := serverapi.UIPreferences{}

	if s.getOptions().UIPreferencesFile == "" {
		return p, nil
	}

	f, err := os.Open(s.getOptions().UIPreferencesFile)
	if os.IsNotExist(err) {
		return p, nil
	}

	if err != nil {
		return p, errors.Wrap(err, "unable to open UI preferences file")
	}

	defer f.Close() //nolint:errcheck

	if err := json.NewDecoder(f).Decode(&p); err != nil {
		return p, errors.Wrap(err, "invalid UI preferences file")
	}

	return p, nil
}

func handleGetUIPreferences(_ context.Context, rc requestContext) (any, *apiError) {
	p, err := getUIPreferencesOrEmpty(rc.srv)
	if err != nil {
		return nil, internalServerError(err)
	}

	return &p, nil
}

func handleSetUIPreferences(_ context.Context, rc requestContext) (any, *apiError) {
	var p serverapi.UIPreferences

	// verify the JSON is valid by unmarshaling it

View on GitHub (pinned to 82495e54b5)