larksuite/cli · error
lockfile: lock already held
Error message
lockfile: lock already held
What it means
Sentinel returned by TryLock when the advisory lockfile already exists and is held by another process; the doc comment marks it as retryable contention. It signals normal concurrency, not corruption - e.g. a second CLI invocation or an already-running event bus owns the lock.
Source
Thrown at internal/lockfile/lockfile.go:21
package lockfile
import (
"errors"
"fmt"
"os"
"path/filepath"
"regexp"
"github.com/larksuite/cli/internal/core"
"github.com/larksuite/cli/internal/vfs"
)
// safeIDChars strips path-traversal chars from app IDs.
var safeIDChars = regexp.MustCompile(`[^a-zA-Z0-9._-]`)
// ErrHeld signals retryable contention; callers errors.Is to distinguish from real failures.
var ErrHeld = errors.New("lockfile: lock already held")
type LockFile struct {
path string
file *os.File
}
func New(path string) *LockFile {
return &LockFile{path: path}
}
// ForSubscribe sanitises appID against path traversal before forming the lock filename.
func ForSubscribe(appID string) (*LockFile, error) {
if appID == "" {
return nil, fmt.Errorf("app ID must not be empty")
}
dir := filepath.Join(core.GetConfigDir(), "locks")
if err := vfs.MkdirAll(dir, 0700); err != nil {
return nil, fmt.Errorf("create lock dir: %w", err)View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Wait for the current holder to finish and retry the lock acquisition
- Treat it as 'already running' and skip spawning a second instance, as busdiscover does for PID files
Defensive patterns
Strategy: retry
When it happens
Trigger: Thrown at internal/lockfile/lockfile.go:21 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/1db0dfa79abae76b.
Report an issue: GitHub.