{"record":{"id":"8ac159ad89578149","repo":"chenhg5/cc-connect","slug":"cannot-open-lock-file-w","errorCode":null,"errorMessage":"cannot open lock file: %w","messagePattern":"cannot open lock file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/cc-connect/instance_lock.go","lineNumber":43,"sourceCode":"// 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)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"another cc-connect instance is already running with config %s\", configPath)\n\t}\n\n\t// Write our PID to the lock file for diagnostics\n\tpid := os.Getpid()","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/cmd/cc-connect/instance_lock.go#L25-L61","documentation":"After ensuring the config directory exists, AcquireInstanceLock opens the lock file .<config>.lock with os.OpenFile(O_CREATE|O_RDWR). Any open failure is wrapped as \"cannot open lock file: %w\". This is an OS-level open error, distinct from the lock-contention error paths.","triggerScenarios":"os.OpenFile(lockPath, os.O_CREATE|os.O_RDWR, 0644) fails: the config directory is not writable, the lock path exists as a directory, or the filesystem is read-only/full.","commonSituations":"A previous crash left a directory named .config.toml.lock in the config dir; the config dir is owned by root after running once with sudo; read-only /etc or NFS mount.","solutions":["Inspect and fix permissions on the config directory (chmod u+w / chown $USER).","If .<config>.lock exists as a directory, remove it: rm -rf <configDir>/.<configBase>.lock.","Check disk space and read-only mount status for the filesystem.","Run cc-connect as the same user that owns the config directory (avoid mixing sudo runs)."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"lockPath := filepath.Join(filepath.Dir(configPath), \".\"+filepath.Base(configPath)+\".lock\")\nif fi, err := os.Stat(lockPath); err == nil && fi.IsDir() {\n    return fmt.Errorf(\"%s is a directory; remove it\", lockPath)\n}\ntest, err := os.OpenFile(lockPath, os.O_CREATE|os.O_RDWR, 0644)\nif err != nil {\n    return err\n}\ntest.Close()","typeGuard":null,"tryCatchPattern":"lock, err := AcquireInstanceLock(configPath)\nif err != nil && strings.Contains(err.Error(), \"cannot open lock file\") {\n    slog.Error(\"lock file unwritable — check dir perms/stale directory\", \"err\", err)\n    os.Exit(1)\n}","preventionTips":["Never run cc-connect with sudo if the config dir belongs to a normal user.","After crashes, verify .<config>.lock is a regular file, not a directory.","Monitor disk space on the volume holding the config."],"tags":["filesystem","permissions","file-open","cli"],"backgroundTag":"file-open-failed","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"}