larksuite/cli · error

create lock dir: %w

Error message

create lock dir: %w

What it means

ForSubscribe creates <config-dir>/locks with mode 0700 via vfs.MkdirAll before writing the lock file; if that fails it wraps the underlying error. This guards all subsequent lock-file creation against a missing or uncreatable config directory.

Source

Thrown at internal/lockfile/lockfile.go:39

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)
	}
	safe := safeIDChars.ReplaceAllString(appID, "_")
	name := filepath.Base(fmt.Sprintf("subscribe_%s.lock", safe))
	path := filepath.Join(dir, name)
	return New(path), nil
}

// TryLock acquires an exclusive non-blocking lock; auto-released on process exit.
func (l *LockFile) TryLock() error {
	if l.file != nil {
		return fmt.Errorf("%w: %s", ErrHeld, l.path)
	}
	f, err := vfs.OpenFile(l.path, os.O_CREATE|os.O_RDWR, 0600)
	if err != nil {
		return fmt.Errorf("open lock file: %w", err)
	}
	if err := tryLockFile(f); err != nil {
		f.Close()

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Check the error wrapped in %w for the concrete cause (permission vs disk vs path).
  2. Point LARKSUITE_CLI_CONFIG_DIR to a writable directory.
  3. Fix permissions on the config dir / home directory (mkdir/chmod as needed).
  4. Free disk space or raise quota if the failure is ENOSPC.

Example fix

// before
export LARKSUITE_CLI_CONFIG_DIR=/root/.config  # read-only container
// after
export LARKSUITE_CLI_CONFIG_DIR=/tmp/lark-config  # writable path
# or: chmod u+rwX ~/.config
Defensive patterns

Strategy: validation

Validate before calling

cfgDir := os.Getenv("LARKSUITE_CLI_CONFIG_DIR")
if cfgDir == "" { cfgDir = filepath.Join(os.Getenv("HOME"), ".config") }
if info, err := os.Stat(cfgDir); err != nil || !info.IsDir() {
    return fmt.Errorf("config dir %q unavailable", cfgDir)
}

Prevention

When it happens

Trigger: vfs.MkdirAll fails while calling lockfile.ForSubscribe — e.g. the config dir is read-only, does not exist and cannot be created, disk full, or permission denied on the user's home/config path.

Common situations: Running in a container with a read-only or non-writable HOME; LARKSUITE_CLI_CONFIG_DIR pointing to an invalid/unwritable path; disk quota exceeded; sandboxed CI runners restricting writes.

Related errors


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/66c8997595a4544b. Report an issue: GitHub.