gastownhall/beads · info
lock already held by another process
Error message
lock already held by another process
What it means
On WASM, errProcessLocked is declared for API parity with the other platforms, but flockExclusive is a no-op that always returns nil — WASM environments are typically single-process and file locking is unsupported. The sentinel can therefore only be matched, not normally produced, on this build target.
Source
Thrown at internal/lockfile/lock_wasm.go:10
//go:build js && wasm
package lockfile
import (
"errors"
"os"
)
var errProcessLocked = errors.New("lock already held by another process")
func flockExclusive(f *os.File) error {
// WASM doesn't support file locking
// In a WASM environment, we're typically single-process anyway
return nil // No-op in WASM
}
// FlockExclusiveNonBlocking attempts to acquire an exclusive lock without blocking.
// In WASM, this is a no-op since we're single-process.
func FlockExclusiveNonBlocking(f *os.File) error {
return nil
}
// FlockExclusiveBlocking acquires an exclusive blocking lock on the file.
// In WASM, this is a no-op since we're single-process.
func FlockExclusiveBlocking(f *os.File) error {
return nil
}View on GitHub (pinned to 71377f2769)
Solutions
- Do not rely on real mutual exclusion in WASM builds; use a JS-side or application-level lock if cross-process exclusion is required
- Keep using lockfile.IsLocked/ErrLockBusy in shared code so behavior stays portable across platforms
- Document that WASM locks are advisory no-ops to avoid false confidence in exclusivity
Example fix
// before
// assumes Acquire excludes other processes on every platform
err := lockfile.Acquire(path)
// after
err := lockfile.Acquire(path)
if runtime.GOOS == "js" {
// locking is a no-op on WASM; enforce exclusion at the app level
} Defensive patterns
Strategy: fallback
Validate before calling
if runtime.GOOS == "js" {
// lockfile is a no-op on wasm; use a JS-side mutex for cross-tab exclusion
} Try / catch
err := lockfile.Acquire(path)
if err != nil && lockfile.IsLocked(err) {
return fallbackApplicationLock() // wasm locks are advisory no-ops
} Prevention
- Never assume real mutual exclusion from lockfile under GOOS=js
- Enforce exclusivity with the host environment (JS mutex, single-threaded runtime) on wasm
- Keep platform differences behind lockfile helpers instead of calling flock helpers directly
When it happens
Trigger: Code paths referencing errProcessLocked/lockfile.IsLocked under GOOS=js/wasm compile and behave the same; in practice the lock functions succeed unconditionally, so this error is essentially unreachable on WASM unless surfaced by shared code that checks it.
Common situations: Cross-compiling bd to WASM (browser/Node) where unix and windows lock implementations are swapped out; tests built for WASM asserting lock behavior that does not apply on that platform.
Related errors
- lock busy: held by another process
- lock already held by another process
- lock already held by another process
- ErrLockHeld
- ErrBusy
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/4dd4371c92116b02.
Report an issue: GitHub.