{"record":{"id":"60641b3d52bcf7d2","repo":"chenhg5/cc-connect","slug":"save-model-w","errorCode":null,"errorMessage":"save model: %w","messagePattern":"save model: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/engine.go","lineNumber":9956,"sourceCode":"// persists the change so reloads keep the selected default.\nfunc (e *Engine) switchModel(target string) (string, error) {\n\treturn e.switchModelOnAgent(e.agent, target, true)\n}\n\n// switchModelOnAgent applies a runtime model selection to the provided agent.\n// When persistConfig is true, config-backed model/provider changes are saved so\n// reloads keep the new default. Workspace-scoped runtime switches pass false.\nfunc (e *Engine) switchModelOnAgent(agent Agent, target string, persistConfig bool) (string, error) {\n\tswitcher, ok := agent.(ModelSwitcher)\n\tif !ok {\n\t\treturn target, nil\n\t}\n\n\tproviderSwitcher, ok := agent.(ProviderSwitcher)\n\tif !ok {\n\t\tif persistConfig && e.modelSaveFunc != nil {\n\t\t\tif err := e.modelSaveFunc(target); err != nil {\n\t\t\t\treturn \"\", fmt.Errorf(\"save model: %w\", err)\n\t\t\t}\n\t\t}\n\t\tswitcher.SetModel(target)\n\t\treturn target, nil\n\t}\n\tactive := providerSwitcher.GetActiveProvider()\n\tif active == nil {\n\t\tif persistConfig && e.modelSaveFunc != nil {\n\t\t\tif err := e.modelSaveFunc(target); err != nil {\n\t\t\t\treturn \"\", fmt.Errorf(\"save model: %w\", err)\n\t\t\t}\n\t\t}\n\t\tswitcher.SetModel(target)\n\t\treturn target, nil\n\t}\n\n\tproviders := providerSwitcher.ListProviders()\n\tupdated, found := SetProviderModel(providers, active.Name, target)","sourceCodeStart":9938,"sourceCodeEnd":9974,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/engine.go#L9938-L9974","documentation":"Error from the model-switch path for agents that do NOT implement ProviderSwitcher: when `persistConfig` is set, the engine calls `e.modelSaveFunc(target)` to persist the chosen model to config, and wraps any failure with \"save model: %w\". The switch still happened in memory — this is purely a persistence failure.","triggerScenarios":"/model <name> (or the model-switch API) with persistConfig=true on a non-provider-switcher agent, and the registered modelSaveFunc returns an error: config file unwritable, TOML serialization failure, or config path misconfigured.","commonSituations":"config.toml is read-only (running as wrong user, read-only mounted volume); CC_CONNECT_CONFIG points at a directory without write permission; disk full.","solutions":["Check write permission on the config file and its directory (`ls -l` the path modelSaveFunc writes to)","Ensure the config volume is writable in containers (not mounted :ro)","Run with persistConfig disabled if you do not want the model choice saved","Inspect the wrapped inner error (%w) for the exact cause — it names the failing write"],"exampleFix":"// before: read-only config path\nconfig_path = \"/etc/cc-connect/config.toml\"  // root-owned, app user cannot write\n\n// after: user-writable config\nconfig_path = \"~/.config/cc-connect/config.toml\"","handlingStrategy":"validation","validationCode":"info, err := os.Stat(cfgPath); if err != nil || info.IsDir() { return err }; f, err := os.OpenFile(cfgPath, os.O_WRONLY, 0); if err != nil { return fmt.Errorf(\"config not writable: %w\", err) }; f.Close()","typeGuard":null,"tryCatchPattern":"Wrap the model-switch call and, on an error containing \"save model:\", fall back to an in-memory-only switch and warn the user the choice is not persisted:\nif _, err := e.SwitchModel(...); err != nil { slog.Warn(\"model switched but not persisted\", \"err\", err) }","preventionTips":["Ensure config.toml and its directory are writable by the cc-connect user","Do not mount the config directory read-only in containers","Check disk space on the config volume","Validate config path settings (CC_CONNECT_CONFIG) point to a real file, not a directory"],"tags":["go","persistence","config","model-switch"],"backgroundTag":"file-write-failed","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}