chenhg5/cc-connect · error
create LaunchAgents dir: %w
Error message
create LaunchAgents dir: %w
What it means
launchdManager.Install creates the user's ~/Library/LaunchAgents directory before writing the plist. If os.MkdirAll on that directory fails, the error is wrapped with 'create LaunchAgents dir:' to identify the failing step. This typically indicates a filesystem-level problem (permissions, path is a file, disk full).
Source
Thrown at daemon/launchd.go:46
type launchdManager struct{}
// CheckLinger always returns true on macOS: launchd user agents persist
// 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)View on GitHub (pinned to 4000b2338a)
Solutions
- Check that ~/Library exists as a directory and is writable: ls -ld ~/Library ~/Library/LaunchAgents
- Remove/rename any non-directory named LaunchAgents at the plist path
- Run the install as the actual user (not root) so the plist lands in the correct LaunchAgents directory
- Inspect the wrapped %w cause in the error for the underlying OS reason
Example fix
// before $ cc-connect daemon install // HOME read-only // after $ chmod u+w ~/Library && cc-connect daemon install
Defensive patterns
Strategy: try-catch
Validate before calling
dir := filepath.Dir(plistPath)
if st, err := os.Stat(dir); err != nil {
// parent missing — verify you can create it
} else if !st.IsDir() {
return fmt.Errorf("%s exists but is not a directory", dir)
} Try / catch
if err := daemon.Install(cfg); err != nil {
var pe *fs.PathError
if errors.As(err, &pe) {
log.Printf("launchd install failed at %s: %v", pe.Path, pe.Err)
}
return err
} Prevention
- Run daemon install as the regular user with a writable HOME
- Ensure ~/Library/LaunchAgents exists as a directory, not a file
- Avoid MDM/security policies blocking writes under ~/Library
When it happens
Trigger: Calling daemon.Install (launchd) when filepath.Dir(launchdPlistPath()) cannot be created with mode 0755 — e.g. ~/Library exists as a regular file, or a component of the path denies write access.
Common situations: Running under an account with a broken/restricted HOME; MDM or security tools locking ~/Library; a stray file named LaunchAgents at the expected path; read-only home volume.
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 log dir: %w
- write plist: %w
- read existing Agy hooks %s: %w
- claudecode: create usage temp dir: %w
- claudecode: chmod per-spawn prompt file 0o644: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/4b5dc4d61f0e18ed.
Report an issue: GitHub.