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
- Make the config file writable (permissions, mount flags, SELinux context)
- Inspect the wrapped inner error for the backend's specific failure
- Avoid concurrent model switches from multiple chats writing the same config
- 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
- Verify the config backend is writable (mount flags, SELinux/ACLs) before enabling persisted provider switching
- Avoid issuing provider/model switches concurrently from multiple chats
- Use simple provider names without characters your config backend mishandles
- Read the wrapped (%w) cause to pinpoint filesystem vs backend failure
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
- save model: %w
- parse existing Agy hooks %s: %w
- marshal Agy hooks overlay: %w
- tmux: 'session' option is required (name of the tmux session
- tmux: session %q does not exist and auto_create is disabled
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/d28b3228b6e76886.
Report an issue: GitHub.