{"record":{"id":"de6c73d73abeb0a6","repo":"chenhg5/cc-connect","slug":"cannot-create-config-directory-w","errorCode":null,"errorMessage":"cannot create config directory: %w","messagePattern":"cannot create config directory: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/cc-connect/instance_lock.go","lineNumber":37,"sourceCode":"\n// AcquireInstanceLock attempts to acquire an exclusive lock for the given config path.\n// If another instance is already running with the same config, it returns an error\n// containing the PID of the existing instance.\n//\n// The lock file is placed in the same directory as the config file, with a name\n// derived from the config path hash. This allows different configs to run simultaneously.\nfunc AcquireInstanceLock(configPath string) (*InstanceLock, error) {\n\t// Create lock file path based on config path\n\tconfigDir := filepath.Dir(configPath)\n\tconfigBase := filepath.Base(configPath)\n\n\t// Use a predictable name based on config filename\n\tlockName := fmt.Sprintf(\".%s.lock\", configBase)\n\tlockPath := filepath.Join(configDir, lockName)\n\n\t// Ensure directory exists\n\tif err := os.MkdirAll(configDir, 0755); err != nil {\n\t\treturn nil, fmt.Errorf(\"cannot create config directory: %w\", err)\n\t}\n\n\t// Open/create the lock file\n\tf, err := os.OpenFile(lockPath, os.O_CREATE|os.O_RDWR, 0644)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"cannot open lock file: %w\", err)\n\t}\n\n\t// Try to acquire exclusive lock (non-blocking)\n\terr = syscall.Flock(int(f.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)\n\tif err != nil {\n\t\t// Lock is held by another process\n\t\tf.Close()\n\n\t\t// Try to read PID from lock file for better error message\n\t\tpid := readPIDFromLockFile(lockPath)\n\t\tif pid > 0 {\n\t\t\treturn nil, fmt.Errorf(\"another cc-connect instance is already running (PID %d) with config %s\", pid, configPath)","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/cmd/cc-connect/instance_lock.go#L19-L55","documentation":"AcquireInstanceLock creates the config directory (os.MkdirAll) before opening its lock file. If the directory cannot be created, the function fails with \"cannot create config directory: %w\". This is an OS-level failure (permissions, read-only filesystem, path is a file) surfaced before locking occurs.","triggerScenarios":"Calling AcquireInstanceLock(configPath) where filepath.Dir(configPath) does not exist and cannot be created: parent dir not writable, a non-directory file occupies the path, or the filesystem is read-only/full.","commonSituations":"Running cc-connect with a config path in a directory the user cannot write to (e.g. /etc or another user's home), a stale file named like the config dir, disk full, or read-only mount after system recovery.","solutions":["Check permissions on the config directory's parent and create it manually: mkdir -p $(dirname <configPath>).","Verify no regular file exists at the config directory path; remove or rename it.","Check disk space (df -h) and mount status (mount | grep ro) for the filesystem holding the config.","Pass a --config path in a writable location (e.g. ~/.config/cc-connect/config.toml)."],"exampleFix":"// before\nf, err := lock(configPath) // fails when ~/.config/cc-connect is unwritable\n// after\n// pre-create with correct ownership, then run\n// mkdir -p ~/.config/cc-connect && chown $USER ~/.config/cc-connect","handlingStrategy":"validation","validationCode":"dir := filepath.Dir(configPath)\nif fi, err := os.Stat(dir); err == nil && !fi.IsDir() {\n    return fmt.Errorf(\"%s is a file, not a directory\", dir)\n}\nif err := os.MkdirAll(dir, 0755); err != nil {\n    return fmt.Errorf(\"config dir not creatable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"lock, err := AcquireInstanceLock(configPath)\nif err != nil && strings.Contains(err.Error(), \"cannot create config directory\") {\n    slog.Error(\"check permissions/ownership of config dir\", \"dir\", filepath.Dir(configPath), \"err\", err)\n    os.Exit(1)\n}","preventionTips":["Run cc-connect as the user who owns the config directory.","Pre-create the config directory with correct permissions during install.","Keep config paths out of root-owned/system directories."],"tags":["filesystem","permissions","mkdir","cli"],"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-14T05:17:10.506Z"}