{"record":{"id":"36a0c74fb076c1c9","repo":"wavetermdev/waveterm","slug":"filemutex-trylock-error-w","errorCode":null,"errorMessage":"filemutex trylock error: %w","messagePattern":"filemutex trylock error: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/wavebase/wavebase-win.go","lineNumber":26,"sourceCode":"import (\n\t\"fmt\"\n\t\"log\"\n\t\"path/filepath\"\n\n\t\"github.com/alexflint/go-filemutex\"\n)\n\nfunc AcquireWaveLock() (FDLock, error) {\n\tdataHomeDir := GetWaveDataDir()\n\tlockFileName := filepath.Join(dataHomeDir, WaveLockFile)\n\tlog.Printf(\"[base] acquiring lock on %s\\n\", lockFileName)\n\tm, err := filemutex.New(lockFileName)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"filemutex new error: %w\", err)\n\t}\n\terr = m.TryLock()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"filemutex trylock error: %w\", err)\n\t}\n\treturn m, nil\n}\n","sourceCodeStart":8,"sourceCodeEnd":30,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/wavebase/wavebase-win.go#L8-L30","documentation":"AcquireWaveLock in pkg/wavebase wraps a failure from filemutex.New's TryLock() — the process could not obtain an exclusive OS-level file lock on the Wave lock file. TryLock returns a non-nil error when the lock file is already held by another process (or an OS-level locking failure occurs). It is thrown at startup so the app never runs two instances against the same data directory.","triggerScenarios":"Calling AcquireWaveLock (typically from main) when another Wave process already holds TryLock on lockFileName; or the underlying syscall (flock/LockFileEx) fails due to filesystem/permissions issues.","commonSituations":"Launching Wave while an existing instance is still running; a stale/crashed process holding the lock; running from a network or read-only filesystem where locking is unsupported; permission problems on the lock file.","solutions":["Check for and close any already-running Wave process, then retry launch","Inspect the wrapped error: if it indicates the lock is simply held, that is the single-instance guard working — reuse the running instance","Verify the lock file directory is writable and on a filesystem supporting file locks (not NFS/SMB)","If a dead process left the file, delete the stale lock file (the lock itself is released by the OS when the process dies)"],"exampleFix":"// before: app exits with 'filemutex trylock error: resource temporarily unavailable'\n// after: detect double-launch before calling\nif !canAcquireLock(lockFileName) {\n    fmt.Println(\"Wave is already running; exiting\")\n    os.Exit(0)\n}\nlock, err := wavebase.AcquireWaveLock(lockFileName)","handlingStrategy":"try-catch","validationCode":"// before launching\nif _, err := os.Stat(lockFilePath); err == nil {\n    if procRunning('waveterm') { fmt.Println(\"already running\"); os.Exit(0) }\n}","typeGuard":null,"tryCatchPattern":"lock, err := wavebase.AcquireWaveLock(name)\nif err != nil {\n    if strings.Contains(err.Error(), \"trylock\") {\n        log.Fatalf(\"another instance holds the lock: %v\", err)\n    }\n    return err\n}","preventionTips":["Ensure single-instance launching (detect existing process before acquire)","Place lock files on local filesystems that support flock/LockFileEx, never NFS/SMB","Verify directory write permissions before startup"],"tags":["file-lock","single-instance","startup","go","windows"],"backgroundTag":"file-lock-already-held","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}