docker/compose · error
cannot take exclusive lock for project %q: %w
Error message
cannot take exclusive lock for project %q: %w
What it means
Returned by `docker compose watch` when locker.NewPidfile(project.Name) fails while creating the project lockfile (typically under ~/.docker/compose/ or the configured lock dir). NewPidfile errors when the pidfile path cannot be created or written (permissions, invalid project name characters, read-only home). The lock enforces a single active watch/up session per project, so creation failure aborts before any watch work.
Source
Thrown at cmd/compose/watch.go:99
// so env_file declared by unrelated services doesn't need to exist
project, err = project.WithServicesEnvironmentResolved(true)
if err != nil {
return err
}
if err := applyPlatforms(project, true); err != nil {
return err
}
build, err := buildOpts.toAPIBuildOptions(nil)
if err != nil {
return err
}
// validation done -- ensure we have the lockfile for this project before doing work
l, err := locker.NewPidfile(project.Name)
if err != nil {
return fmt.Errorf("cannot take exclusive lock for project %q: %w", project.Name, err)
}
if err := l.Lock(); err != nil {
return fmt.Errorf("cannot take exclusive lock for project %q: %w", project.Name, err)
}
if !watchOpts.noUp {
for index, service := range project.Services {
if service.Build != nil && service.Develop != nil {
service.PullPolicy = types.PullPolicyBuild
}
project.Services[index] = service
}
upOpts := api.UpOptions{
Create: api.CreateOptions{
Build: &build,
Services: services,
RemoveOrphans: false,
Recreate: api.RecreateDiverged,View on GitHub (pinned to ddc4b044b6)
Solutions
- Inspect the wrapped error's cause — it names the underlying file operation that failed.
- Fix permissions on the lock directory (commonly ~/.docker/compose or $XDG-style lockdir): `chmod`/`chown` it to the running user.
- If HOME is read-only (containers/CI), mount or point the lock location at a writable path, or run as a user with a writable home.
- As a last resort remove a stale/corrupt pidfile for the project after verifying no watch process is running.
Example fix
# before (lockdir not writable by current user) docker compose watch # after chmod -R u+w ~/.docker/compose # or run as the owning user docker compose watch
Defensive patterns
Strategy: try-catch
Validate before calling
# ensure the lock dir is writable before watch
LOCKDIR="$HOME/.docker/compose"
[ -w "$LOCKDIR" ] || { echo "lock dir not writable: $LOCKDIR" >&2; exit 2; } Try / catch
err := runWatch(...); if err != nil && strings.Contains(err.Error(), "cannot take exclusive lock") { /* inspect wrapped cause: perms/path; fix lockdir ownership or redirect to writable HOME; do NOT blindly retry */ } Prevention
- Run watch as the user owning ~/.docker.
- In containers/CI, ensure HOME is writable or mount the lock dir.
- Read the wrapped error — creation failure vs lock contention have different fixes.
When it happens
Trigger: Unwritable lock directory (permissions changed, read-only filesystem, sandboxed container with read-only HOME); a project name that sanitizes to a path with invalid characters; disk-full or SELinux denial on the lockdir; running watch as a different user than the one owning existing lock files.
Common situations: Running `docker compose watch` inside a dev container or CI where HOME is read-only; root vs non-root ownership conflicts on the lock directory; systems with restrictive umask/ACLs on ~/.docker.
Related errors
- --wait cannot be combined with --abort-on-container-exit, --
- --detach cannot be combined with --abort-on-container-exit,
- --no-build and --watch are incompatible
- failed to access env file %s: %w
- resolving symlink for %q: %w
AI-assisted analysis of docker/compose@ddc4b044b6 (2026-08-15).
Data as JSON: /api/errors/6a44914a9dae8189.
Report an issue: GitHub.