wavetermdev/waveterm · critical

filemutex new error: %w

Error message

filemutex new error: %w

What it means

The Windows implementation of AcquireWaveLock creates a filemutex on <WaveDataDir>/<WaveLockFile> to ensure only one Wave instance runs. filemutex.New fails when the lock file path cannot be set up (invalid path, directory missing, or OS-level CreateFile failure), wrapped as 'filemutex new error: %w'.

Source

Thrown at pkg/wavebase/wavebase-win.go:22

//go:build windows

package wavebase

import (
	"fmt"
	"log"
	"path/filepath"

	"github.com/alexflint/go-filemutex"
)

func AcquireWaveLock() (FDLock, error) {
	dataHomeDir := GetWaveDataDir()
	lockFileName := filepath.Join(dataHomeDir, WaveLockFile)
	log.Printf("[base] acquiring lock on %s\n", lockFileName)
	m, err := filemutex.New(lockFileName)
	if err != nil {
		return nil, fmt.Errorf("filemutex new error: %w", err)
	}
	err = m.TryLock()
	if err != nil {
		return nil, fmt.Errorf("filemutex trylock error: %w", err)
	}
	return m, nil
}

View on GitHub (pinned to a4447c1563)

Solutions

  1. Read the wrapped %w error for the exact Windows error code
  2. Ensure the data directory exists: create GetWaveDataDir()'s path (os.MkdirAll) before acquiring the lock
  3. Check/fix the WAVE_DATA_DIR override to a valid, writable path
  4. Run the app as a user with write access to the data directory

Example fix

// before
lock, err := wavebase.AcquireWaveLock() // data dir missing
// after
if err := os.MkdirAll(wavebase.GetWaveDataDir(), 0755); err != nil {
    return err
}
lock, err := wavebase.AcquireWaveLock()
Defensive patterns

Strategy: try-catch

Validate before calling

dataDir := wavebase.GetWaveDataDir()
if err := os.MkdirAll(dataDir, 0755); err != nil {
    return fmt.Errorf("cannot prepare data dir %s: %w", dataDir, err)
}
if err := unix.Access(dataDir, unix.W_OK); err != nil {
    return fmt.Errorf("data dir not writable: %w", err)
}

Type guard

func dataDirReady() bool {
    dir := wavebase.GetWaveDataDir()
    info, err := os.Stat(dir)
    return err == nil && info.IsDir()
}

Try / catch

lock, err := wavebase.AcquireWaveLock()
if err != nil {
    if strings.Contains(err.Error(), "filemutex new error") {
        // repair path: ensure data dir exists, then retry once
        os.MkdirAll(wavebase.GetWaveDataDir(), 0755)
        lock, err = wavebase.AcquireWaveLock()
    }
    if err != nil { return err }
}

Prevention

When it happens

Trigger: Calling AcquireWaveLock at startup when GetWaveDataDir() returns a path that does not exist or is not writable, the path contains illegal characters, or filemutex cannot create/open the lock file on Windows (ERROR_PATH_NOT_FOUND, access denied).

Common situations: WAVE_DATA_DIR env var overridden to a nonexistent or invalid directory; data dir deleted by cleanup tools while the app runs; path with characters Windows rejects; running from a context without permission to the data directory (service account, restricted user).

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/000e378c7b61d137. Report an issue: GitHub.