{"record":{"id":"7813c68ebb63bb39","repo":"chenhg5/cc-connect","slug":"create-temp-file-w","errorCode":null,"errorMessage":"create temp file: %w","messagePattern":"create temp file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"config/config.go","lineNumber":3717,"sourceCode":"// FormatConfigFile reads the config file at the given path, formats it, and\n// writes it back. It validates the TOML syntax before writing.\nfunc FormatConfigFile(path string) error {\n\tdata, err := os.ReadFile(path)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"read config: %w\", err)\n\t}\n\tcfg := &Config{}\n\tif err := toml.Unmarshal(data, cfg); err != nil {\n\t\treturn fmt.Errorf(\"invalid TOML: %w\", err)\n\t}\n\tformatted := formatTOML(string(data))\n\tif formatted == string(data) {\n\t\treturn nil\n\t}\n\tdir := filepath.Dir(path)\n\ttmp, err := os.CreateTemp(dir, \".config-*.tmp\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"create temp file: %w\", err)\n\t}\n\ttmpPath := tmp.Name()\n\tif _, err := tmp.WriteString(formatted); err != nil {\n\t\ttmp.Close()\n\t\tos.Remove(tmpPath)\n\t\treturn fmt.Errorf(\"write formatted config: %w\", err)\n\t}\n\tif err := tmp.Sync(); err != nil {\n\t\ttmp.Close()\n\t\tos.Remove(tmpPath)\n\t\treturn err\n\t}\n\tif err := tmp.Close(); err != nil {\n\t\tos.Remove(tmpPath)\n\t\treturn err\n\t}\n\treturn os.Rename(tmpPath, path)\n}","sourceCodeStart":3699,"sourceCodeEnd":3735,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/config/config.go#L3699-L3735","documentation":"When the formatted TOML differs from the input, FormatConfigFile writes atomically via a .config-*.tmp file created with os.CreateTemp in the file's directory. CreateTemp failure (unwritable directory, missing dir, full disk) is wrapped as \"create temp file: %w\" and the original file is left unchanged.","triggerScenarios":"os.CreateTemp(filepath.Dir(path), \".config-*.tmp\") fails in FormatConfigFile (config/config.go:3717): the target directory is read-only, was deleted, or the filesystem is out of space/inodes.","commonSituations":"Formatting a config in /etc or a read-only mount without elevated privileges; tmpfs full; directory removed by another process between read and write.","solutions":["Ensure the directory containing the config is writable by the current user (`ls -ld <dir>`).","Run with elevated permissions when formatting system-wide configs (e.g. sudo for /etc paths).","Free disk space if the filesystem is full."],"exampleFix":"// before (shell)\ncc-connect config format /etc/cc-connect/config.toml   # EACCES on temp file\n// after\nsudo cc-connect config format /etc/cc-connect/config.toml","handlingStrategy":"try-catch","validationCode":"dir := filepath.Dir(path)\ninfo, err := os.Stat(dir)\nif err != nil || !info.IsDir() {\n    return fmt.Errorf(\"config dir missing: %s\", dir)\n}\nprobe, err := os.CreateTemp(dir, \".fmt-probe-*\")\nif err != nil {\n    return fmt.Errorf(\"dir not writable: %w\", err)\n}\nprobe.Close(); os.Remove(probe.Name())","typeGuard":null,"tryCatchPattern":"if err := config.FormatConfigFile(path); err != nil {\n    var pe *fs.PathError\n    if errors.As(err, &pe) && strings.Contains(err.Error(), \"create temp file\") && errors.Is(pe.Err, fs.ErrPermission) {\n        return fmt.Errorf(\"need write access to %s (try sudo)\", filepath.Dir(path))\n    }\n    return err\n}","preventionTips":["Format configs only in directories writable by the current user; use sudo for /etc paths.","Don't place config.toml on read-only or tmpfs mounts.","Watch inode usage, not just bytes — full inodes also break CreateTemp."],"tags":["config","file-io","temp-file","permissions"],"backgroundTag":"file-write-permission-denied","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"}