chenhg5/cc-connect · error
create log dir: %w
Error message
create log dir: %w
What it means
launchdManager.Install also ensures the directory for the configured LogFile exists (creating it with 0755) so launchd's stdout/stderr redirection does not fail. Failure to create that directory is wrapped as 'create log dir:'. The wrapped cause contains the underlying OS error.
Source
Thrown at daemon/launchd.go:49
// independently of login sessions, so no "linger" warning is needed.
func CheckLinger() (enabled bool, user string) {
return true, ""
}
func newPlatformManager() (Manager, error) {
return &launchdManager{}, nil
}
func (*launchdManager) Platform() string { return "launchd" }
func (m *launchdManager) Install(cfg Config) error {
plistPath := launchdPlistPath()
if err := os.MkdirAll(filepath.Dir(plistPath), 0755); err != nil {
return fmt.Errorf("create LaunchAgents dir: %w", err)
}
if err := os.MkdirAll(filepath.Dir(cfg.LogFile), 0755); err != nil {
return fmt.Errorf("create log dir: %w", err)
}
// Unload existing service first (ignore errors) so we do not leave a stale
// job behind when switching between GUI and headless sessions.
bootoutLaunchdTargets()
plist := buildPlist(cfg)
// 0600: plist may contain captured secret values (config.toml ${ENV}
// placeholders and any EnvDiscoverer extension output). User-only
// LaunchAgents path; root can still read but that is the user's own
// machine boundary. os.WriteFile only applies perm on create, so
// Chmod afterwards is required to harden reinstalls of files that
// pre-existed at 0644 from earlier cc-connect versions.
if err := os.WriteFile(plistPath, []byte(plist), 0600); err != nil {
return fmt.Errorf("write plist: %w", err)
}
if err := os.Chmod(plistPath, 0600); err != nil {
return fmt.Errorf("chmod plist: %w", err)View on GitHub (pinned to 4000b2338a)
Solutions
- Set LogFile to a user-writable location (default ~/Library/Logs/...) in the daemon config
- Create the log directory manually and verify permissions
- Ensure no regular file occupies a path component of the LogFile directory
- Check the wrapped %w cause (EACCES/ENOTDIR/etc.) for the exact OS reason
Example fix
// before logFile = "/var/log/cc-connect.log" // SIP-protected // after logFile = "/Users/me/Library/Logs/cc-connect.log"
Defensive patterns
Strategy: validation
Validate before calling
logDir := filepath.Dir(cfg.LogFile)
if st, err := os.Stat(logDir); err == nil && !st.IsDir() {
return fmt.Errorf("log dir path %s is a file", logDir)
}
if err := os.MkdirAll(logDir, 0755); err != nil {
return fmt.Errorf("cannot prepare log dir: %w", err)
} Try / catch
if err := daemon.Install(cfg); err != nil {
if strings.Contains(err.Error(), "create log dir") {
// fix cfg.LogFile to a user-writable path and retry
}
return err
} Prevention
- Configure LogFile under the user's home (~/Library/Logs)
- Never point LogFile at SIP-protected paths like /var/log on macOS
- Verify no regular file occupies a log-dir path component
When it happens
Trigger: Calling daemon.Install (launchd) with Config.LogFile whose parent directory cannot be created — e.g. LogFile points into a non-writable path like /var/log on macOS (SIP-protected) or a path component that is a regular file.
Common situations: Config copied from a Linux systemd setup with LogFile=/var/log/cc-connect.log; HOME misconfigured so ~/Library/Logs cannot be created; a file named 'Logs' blocking the directory path.
Understand the failure class
Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.
Related errors
- create LaunchAgents dir: %w
- write plist: %w
- cannot detect binary path: %w
- cannot detect working directory: %w
- create Agy permission overlay: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/a5efd850b7dd2876.
Report an issue: GitHub.