chenhg5/cc-connect · error

save provider model %q: %w

Error message

save provider model %q: %w

What it means

Error from the ProviderSwitcher path of model switching: after updating the provider's model list, the engine calls `e.providerModelSaveFunc(active.Name, target)` to persist which model is active for which provider; any failure is wrapped as "save provider model %q: %w". The in-memory switch still succeeded; only the durable save failed.

Source

Thrown at core/engine.go:9985

			}
		}
		switcher.SetModel(target)
		return target, nil
	}

	providers := providerSwitcher.ListProviders()
	updated, found := SetProviderModel(providers, active.Name, target)
	if !found {
		switcher.SetModel(target)
		return target, nil
	}
	if !persistConfig {
		switcher.SetModel(target)
		return target, nil
	}
	if persistConfig && e.providerModelSaveFunc != nil {
		if err := e.providerModelSaveFunc(active.Name, target); err != nil {
			return "", fmt.Errorf("save provider model %q: %w", active.Name, err)
		}
	}
	providerSwitcher.SetProviders(updated)
	switcher.SetModel(target)
	providerSwitcher.SetActiveProvider(active.Name)
	return target, nil
}

func (e *Engine) cmdReasoning(p Platform, msg *Message, args []string) {
	agent, sessions, _, err := e.commandContext(p, msg)
	if err != nil {
		e.reply(p, msg.ReplyCtx, e.i18n.Tf(MsgWsResolutionError, err))
		return
	}

	switcher, ok := agent.(ReasoningEffortSwitcher)
	if !ok {
		e.reply(p, msg.ReplyCtx, e.i18n.T(MsgReasoningNotSupported))

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Make the config file writable (permissions, mount flags, SELinux context)
  2. Inspect the wrapped inner error for the backend's specific failure
  3. Avoid concurrent model switches from multiple chats writing the same config
  4. Use a non-persisting switch (persistConfig=false) as a temporary workaround

Example fix

// before: k8s volume mounted read-only
volumeMounts:
  - mountPath: /root/.config/cc-connect
    readOnly: true

// after: writable config volume
volumeMounts:
  - mountPath: /root/.config/cc-connect
    readOnly: false
Defensive patterns

Strategy: validation

Validate before calling

f, err := os.OpenFile(cfgPath, os.O_APPEND|os.O_WRONLY, 0); if err != nil { return fmt.Errorf("provider model save will fail, config unwritable: %w", err) }; f.Close()

Try / catch

if _, err := e.SwitchProviderModel(provider, model); err != nil { slog.Warn("provider model not persisted", "provider", provider, "err", err); /* retry with persistConfig=false */ }

Prevention

When it happens

Trigger: /model or /provider switch on an agent implementing ProviderSwitcher with persistConfig=true, where providerModelSaveFunc errors: cannot write the config file, provider name contains characters that break serialization, or the config backend rejects the update.

Common situations: Read-only config mount in Docker/K8s; SELinux or ACL blocking the write; concurrent edits to config.toml causing a write conflict; provider name with characters unsupported by the save backend.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/d28b3228b6e76886. Report an issue: GitHub.