nsqio/nsq · critical
failed to lock data-path: %v
Error message
failed to lock data-path: %v
What it means
nsqd takes an exclusive flock (LOCK_EX|LOCK_NB, see internal/dirlock) on its data directory at startup to guarantee a single writer per --data-path. This error means the lock could not be acquired: most commonly another live nsqd already owns the directory (the underlying error text says 'possibly in use by another instance of nsqd'), or the directory could not even be opened (missing, not a directory, no permissions).
Source
Thrown at nsqd/nsqd.go:108
startTime: time.Now(),
topicMap: make(map[string]*Topic),
exitChan: make(chan int),
notifyChan: make(chan interface{}),
optsNotificationChan: make(chan struct{}, 1),
dl: dirlock.New(dataPath),
}
n.ctx, n.ctxCancel = context.WithCancel(context.Background())
httpcli := http_api.NewClient(nil, opts.HTTPClientConnectTimeout, opts.HTTPClientRequestTimeout)
n.ci = clusterinfo.New(n.logf, httpcli)
n.lookupPeers.Store([]*lookupPeer{})
n.swapOpts(opts)
n.errValue.Store(errStore{})
err = n.dl.Lock()
if err != nil {
return nil, fmt.Errorf("failed to lock data-path: %v", err)
}
if opts.MaxDeflateLevel < 1 || opts.MaxDeflateLevel > 9 {
return nil, errors.New("--max-deflate-level must be [1,9]")
}
if opts.ID < 0 || opts.ID >= 1024 {
return nil, errors.New("--node-id must be [0,1024)")
}
if opts.TLSClientAuthPolicy != "" && opts.TLSRequired == TLSNotRequired {
opts.TLSRequired = TLSRequired
}
tlsConfig, err := buildTLSConfig(opts)
if err != nil {
return nil, fmt.Errorf("failed to build TLS config - %s", err)
}View on GitHub (pinned to 85cf10c09c)
Solutions
- Find the other holder: pgrep -a nsqd, fuser -v /var/lib/nsqd, then stop it or give this instance its own --data-path
- Verify the directory exists, is a directory, and is readable/writable by the nsqd user: ls -ld /var/lib/nsqd
- If using restart wrappers, add a pre-start check that waits for the old pid to exit
- In containers, ensure the volume is mounted before nsqd starts
Example fix
# before (two instances, same path) nsqd --data-path=/var/lib/nsqd nsqd --data-path=/var/lib/nsqd # second start -> failed to lock data-path # after nsqd --data-path=/var/lib/nsqd-a nsqd --data-path=/var/lib/nsqd-b
Defensive patterns
Strategy: try-catch
Validate before calling
// pre-start: ensure path exists and is not already locked
if fi, err := os.Stat(dataPath); err != nil || !fi.IsDir() {
log.Fatalf("data path %s missing or not a directory", dataPath)
} Try / catch
n, err := nsqd.New(opts)
if err != nil {
if strings.Contains(err.Error(), "failed to lock data-path") {
// another nsqd owns the directory (or path unopenable):
// stop the other instance or use a distinct --data-path; do not retry in place
}
log.Fatal(err)
} Prevention
- Give every nsqd instance a unique --data-path (and --node-id)
- Ensure the data directory is mounted before the service starts
- Use start-limit / pre-stop semantics so restarts never overlap the flock window
When it happens
Trigger: Starting a second nsqd with the same --data-path; the directory does not exist or nsqd's user lacks read permission on it; a supervising system (systemd restart, Docker retry) launching a replacement before the old process fully exited and released the flock.
Common situations: Copy-pasting a unit file for a second node without changing --data-path; accidental double-start via service manager plus manual run; k8s liveness probe storm causing overlapping restarts; moving data-path to a mount that is not yet mounted (path missing).
Related errors
- E_REQ_FAILED
- E_SUB_FAILED
- ID not in flight
- client does not own message
- failed to append certificate to pool
AI-assisted analysis of nsqio/nsq@85cf10c09c (2026-08-16).
Data as JSON: /api/errors/78604c553183a732.
Report an issue: GitHub.