{"record":{"id":"cffe2805c00006ae","repo":"chenhg5/cc-connect","slug":"chmod-unit-file-w","errorCode":null,"errorMessage":"chmod unit file: %w","messagePattern":"chmod unit file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"daemon/systemd.go","lineNumber":73,"sourceCode":"\t\treturn fmt.Errorf(\"create systemd dir: %w\", err)\n\t}\n\tif err := os.MkdirAll(filepath.Dir(cfg.LogFile), 0755); err != nil {\n\t\treturn fmt.Errorf(\"create log dir: %w\", err)\n\t}\n\n\tunit := m.buildUnit(cfg)\n\t// 0600: unit file may contain captured secret values (config.toml ${ENV}\n\t// placeholders and any EnvDiscoverer extension output). For system-level\n\t// units (/etc/systemd/system/) the file is owned by root and remains\n\t// readable by root only; for user-level units under\n\t// ~/.config/systemd/user it remains owner-only. WriteFile only applies\n\t// perm on create, so Chmod afterwards is required to harden reinstalls\n\t// of pre-existing 0644 units from earlier cc-connect versions.\n\tif err := os.WriteFile(unitPath, []byte(unit), 0600); err != nil {\n\t\treturn fmt.Errorf(\"write unit file: %w\", err)\n\t}\n\tif err := os.Chmod(unitPath, 0600); err != nil {\n\t\treturn fmt.Errorf(\"chmod unit file: %w\", err)\n\t}\n\n\tfor _, cmdArgs := range [][]string{\n\t\tm.sysArgs(\"daemon-reload\"),\n\t\tm.sysArgs(\"enable\", systemdServiceName),\n\t\tm.sysArgs(\"restart\", systemdServiceName),\n\t} {\n\t\tif out, err := runSystemctl(cmdArgs...); err != nil {\n\t\t\treturn fmt.Errorf(\"systemctl %s: %s (%w)\", strings.Join(cmdArgs, \" \"), out, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (m *systemdManager) Uninstall() error {\n\tif _, err := runSystemctl(m.sysArgs(\"disable\", \"--now\", systemdServiceName)...); err != nil {\n\t\tslog.Warn(\"systemd: disable failed\", \"error\", err)","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/daemon/systemd.go#L55-L91","documentation":"Install() wraps os.Chmod failure when hardening the unit file to 0600 after writing it. WriteFile only applies permissions on create, so Chmod is required to tighten pre-existing 0644 units from older cc-connect versions; if Chmod fails the unit would be left world-readable despite containing secrets.","triggerScenarios":"Calling Install over an existing unit file whose ownership prevents Chmod (file owned by another user), or on a filesystem that does not support chmod (some network/Windows mounts).","commonSituations":"Previous unit installed as root, now reinstalling as a different user; reinstalling on a WSL mount or FAT/NTFS volume; stale root-owned unit from an old version.","solutions":["Run as the same user (or root) that owns the existing unit file.","Remove the stale unit first: `sudo rm /etc/systemd/system/cc-connect.service`, then reinstall.","Check ownership: `ls -l <unitPath>` and `sudo chown` if needed.","Verify the filesystem supports permission changes."],"exampleFix":"// before\nmgr.Install(cfg) // chmod unit file: operation not permitted (root-owned unit)\n// after\nexec.Command(\"sudo\", \"rm\", \"/etc/systemd/system/cc-connect.service\").Run()\nmgr.Install(cfg)","handlingStrategy":"validation","validationCode":"unitPath := mgr.unitPath()\nif fi, err := os.Stat(unitPath); err == nil {\n    if st, err := os.Stat(unitPath); err == nil && st.Uid() != uint32(os.Getuid()) && os.Getuid() != 0 {\n        return fmt.Errorf(\"existing unit owned by uid %d; rerun as root\", st.Uid())\n    }\n}","typeGuard":"func ownsFile(path string) bool {\n    fi, err := os.Stat(path)\n    if err != nil { return true }\n    return fi.Sys().(*syscall.Stat_t).Uid == uint32(os.Getuid())\n}","tryCatchPattern":"if err := mgr.Install(cfg); err != nil {\n    if strings.Contains(err.Error(), \"chmod unit file\") {\n        _ = os.Remove(mgr.unitPath()) // drop stale unit and retry as correct user\n        return mgr.Install(cfg)\n    }\n    return err\n}","preventionTips":["Always reinstall with the same privilege level used originally (root vs user).","Delete stale units before switching install modes.","Avoid unit directories on filesystems without chmod support (WSL /mnt/c, FAT).","Verify resulting permissions after install: stat -c %a <unitPath>."],"tags":["go","systemd","permissions","security"],"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-14T00:17:10.932Z"}