{"record":{"id":"be25d0dcf4d18db0","repo":"alibaba/open-code-review","slug":"create-config-dir-w","errorCode":null,"errorMessage":"create config dir: %w","messagePattern":"create config dir: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/opencodereview/provider_cmd.go","lineNumber":422,"sourceCode":"\t\tif !llm.ModelListContains(registryModels, selectedModel) {\n\t\t\tentry.Models = ensureModelInList(entry.Models, selectedModel)\n\t\t}\n\t\tcfg.Providers[cfg.Provider] = entry\n\t}\n\tcfg.Model = selectedModel\n\n\tif err := saveConfig(configPath, cfg); err != nil {\n\t\treturn err\n\t}\n\n\tfmt.Printf(\"\\nModel set to: %s\\n\", selectedModel)\n\treturn nil\n}\n\nfunc saveConfig(path string, cfg *Config) error {\n\tdir := filepath.Dir(path)\n\tif err := os.MkdirAll(dir, 0o755); err != nil {\n\t\treturn fmt.Errorf(\"create config dir: %w\", err)\n\t}\n\tdata, err := json.MarshalIndent(cfg, \"\", \"    \")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"marshal config: %w\", err)\n\t}\n\tif err := os.WriteFile(path, data, 0o600); err != nil {\n\t\treturn fmt.Errorf(\"write config: %w\", err)\n\t}\n\tif err := os.Chmod(path, 0o600); err != nil {\n\t\treturn fmt.Errorf(\"chmod config: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc maskKey(key string) string {\n\tif key == \"\" {\n\t\treturn \"(not set)\"\n\t}","sourceCodeStart":404,"sourceCodeEnd":440,"githubUrl":"https://github.com/alibaba/open-code-review/blob/5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f/cmd/opencodereview/provider_cmd.go#L404-L440","documentation":"saveConfig creates the parent directory of the config file with os.MkdirAll(dir, 0o755) before writing; if that fails the error is wrapped as \"create config dir\". This is an I/O/permission failure on the filesystem, raised before any JSON is produced.","triggerScenarios":"Calling saveConfig (via ocr config set, unset commands, or the provider/model TUIs) when the config directory cannot be created — e.g. path is inside a read-only directory, a file exists where a directory is expected, or permission is denied.","commonSituations":"HOME set to a non-writable path; config path pointing under a file like /etc/passwd/config.json; disk full or sandboxed CI runners with restricted write access.","solutions":["Check permissions on the parent directory and ensure the user can create the config dir","Ensure the config path's parent is a directory, not an existing file","Fix HOME/XDG or pass a config path in a writable location","Free disk space if the filesystem is full"],"exampleFix":"// before\nOCR_CONFIG=/etc/ocr/config.json ocr config set provider openai\n// error: create config dir: mkdir /etc/ocr: permission denied\n// after\nOCR_CONFIG=~/.config/ocr/config.json ocr config set provider openai","handlingStrategy":"validation","validationCode":"dir := filepath.Dir(cfgPath)\nif info, err := os.Stat(dir); err == nil && !info.IsDir() {\n    return fmt.Errorf(\"%s exists and is not a directory\", dir)\n}\nif err := os.MkdirAll(dir, 0o755); err != nil {\n    return fmt.Errorf(\"cannot create config dir %s: %w\", dir, err)\n}","typeGuard":null,"tryCatchPattern":"if err := saveConfig(path, cfg); err != nil {\n    var pe *os.PathError\n    if errors.As(err, &pe) && errors.Is(pe.Err, fs.ErrPermission) {\n        fmt.Fprintf(os.Stderr, \"no permission for %s — check ownership/HOME\\n\", path)\n    }\n    return err\n}","preventionTips":["Keep config under a writable $HOME/.config path","Never point the config path at a location where the parent is a file","Avoid running the CLI as root in a way that creates root-owned config dirs","Check disk space in monitoring before bulk config automation"],"tags":["filesystem","permissions","config"],"backgroundTag":"mkdir-permission-denied","analyzedSha":"5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f","analyzedAt":"2026-09-02T02:08:09.116Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}