charmbracelet/crush · error

failed to update preferred large model: %w

Error message

failed to update preferred large model: %w

What it means

When resolveSelectedModels applies a fallback correction to the preferred large model (e.g. the selected model no longer exists and was swapped), Load() persists that correction to the global-scope config via store.updateLocked. If the write fails, Load aborts with this wrapped error.

Source

Thrown at internal/config/load.go:154

	if !cfg.IsConfigured() {
		slog.Warn("No providers configured")
		return store, nil
	}

	resolved, err := resolveSelectedModels(cfg, store.knownProviders)
	if err != nil {
		return nil, fmt.Errorf("failed to configure selected models: %w", err)
	}
	cfg.Models[SelectedModelTypeLarge] = resolved.Large
	cfg.Models[SelectedModelTypeSmall] = resolved.Small

	// Persist any fallback corrections while we still hold writeMu.
	if resolved.LargeFallback {
		if err := store.updateLocked(ScopeGlobal, func(c *Config) map[string]any {
			return store.updatePreferredModelFields(c, SelectedModelTypeLarge, resolved.Large)
		}); err != nil {
			return nil, fmt.Errorf("failed to update preferred large model: %w", err)
		}
	}
	if resolved.SmallFallback {
		if err := store.updateLocked(ScopeGlobal, func(c *Config) map[string]any {
			return store.updatePreferredModelFields(c, SelectedModelTypeSmall, resolved.Small)
		}); err != nil {
			return nil, fmt.Errorf("failed to update preferred small model: %w", err)
		}
	}
	store.SetupAgents()

	// Capture initial staleness snapshot
	// Capture initial staleness snapshot. Track every discovered config path,
	// not just the ones that loaded, so a config file created after startup
	// (e.g. a crushrc added mid-session) is detected as a change.
	store.captureStalenessSnapshot(append(slices.Clone(configPaths), loadedPaths...))

	return store, nil

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Check write permissions on the global config file/directory and fix with chmod/chown
  2. Fix the global config content if it is corrupted (validate JSON)
  3. Free disk space if the disk is full
  4. Run crush once with correct permissions so the fallback model is persisted, instead of ignoring the correction

Example fix

// before
$ ls -l ~/.config/crush/crush.json
-r--r--r-- ... (read-only)
// after
$ chmod u+w ~/.config/crush/crush.json
crush  // loads and persists corrected model
Defensive patterns

Strategy: try-catch

Validate before calling

fi, err := os.Stat(globalConfigPath)
if err == nil && fi.Mode().Perm()&0o200 == 0 {
    return fmt.Errorf("global config %s is not writable", globalConfigPath)
}

Try / catch

store, err := config.Load(ctx, opts)
if err != nil {
    if strings.Contains(err.Error(), "failed to update preferred large model:") {
        // global config not writable; chmod or fix disk, then retry
        return fmt.Errorf("fix global config permissions: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: resolved.LargeFallback is true and store.updateLocked(ScopeGlobal, ...) returns an error — typically a file write/permission failure or marshaling error on the global config.

Common situations: Global config file is read-only or owned by another user; disk full; global config corrupted so re-marshaling fails; running in a sandbox where the config dir is not writable.

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/eb9512fc85ecb2f0. Report an issue: GitHub.