{"record":{"id":"f97ec3a7427350b6","repo":"chenhg5/cc-connect","slug":"create-systemd-dir-w","errorCode":null,"errorMessage":"create systemd dir: %w","messagePattern":"create systemd dir: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"daemon/systemd.go","lineNumber":55,"sourceCode":"\n\tif err := checkSystemdRunning(false); err != nil {\n\t\treturn nil, err\n\t}\n\treturn &systemdManager{system: false}, nil\n}\n\nfunc (m *systemdManager) Platform() string {\n\tif m.system {\n\t\treturn \"systemd (system)\"\n\t}\n\treturn \"systemd (user)\"\n}\n\nfunc (m *systemdManager) Install(cfg Config) error {\n\tunitPath := m.unitPath()\n\n\tif err := os.MkdirAll(filepath.Dir(unitPath), 0755); err != nil {\n\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)","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/daemon/systemd.go#L37-L73","documentation":"Install() wraps the os.MkdirAll failure for the systemd unit directory (e.g. /etc/systemd/system or ~/.config/systemd/user) in this error via fmt.Errorf with %w. It means the directory holding the cc-connect .service unit could not be created, typically due to filesystem permissions or a read-only root. It aborts the whole install before any unit file is written.","triggerScenarios":"Calling Install when the parent of unitPath cannot be created: insufficient privileges for /etc/systemd/system, a read-only filesystem, or a path component that is a regular file instead of a directory.","commonSituations":"Running `cc-connect install` as a non-root user for a system-level install; running inside a container with a read-only /etc; a stale file (not directory) sitting at ~/.config/systemd.","solutions":["Run the install command with root privileges (sudo) for a system-level unit.","Check the target path: if a file exists where the directory should be, remove/rename it.","Verify the filesystem is writable (not mounted ro): `mount | grep /etc`.","Use a user-level manager (systemd --user) which writes under ~/.config and needs no root."],"exampleFix":"// before\nerr := mgr.Install(cfg) // fails: create systemd dir: permission denied\n// after\nif os.Geteuid() != 0 && strings.HasPrefix(mgr.unitPath(), \"/etc/\") {\n    return fmt.Errorf(\"system install requires root; use --user\")\n}\nerr := mgr.Install(cfg)","handlingStrategy":"try-catch","validationCode":"unitDir := filepath.Dir(mgr.unitPath())\nif fi, err := os.Stat(unitDir); err == nil && !fi.IsDir() {\n    return fmt.Errorf(\"%s exists and is not a directory\", unitDir)\n}\nif err := os.MkdirAll(unitDir, 0755); err != nil {\n    return fmt.Errorf(\"cannot create unit dir: %w\", err)\n}","typeGuard":"func canWriteDir(path string) bool {\n    fi, err := os.Stat(path)\n    return err == nil && fi.IsDir() && fi.Mode().Perm()&0200 != 0\n}","tryCatchPattern":"if err := mgr.Install(cfg); err != nil {\n    var pe *fs.PathError\n    if errors.As(err, &pe) && errors.Is(pe.Err, fs.ErrPermission) {\n        return fmt.Errorf(\"need root: rerun with sudo (%w)\", err)\n    }\n    return err\n}","preventionTips":["Check for root (os.Geteuid()==0) before system-level installs.","Stat the target directory before install to catch file-instead-of-directory conflicts.","Prefer user-level units under ~/.config when running unprivileged.","Handle %w-wrapped errors with errors.As/errors.Is, never string matching."],"tags":["go","systemd","filesystem","permissions"],"backgroundTag":"mkdir-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"}