docker/compose · error
process still running
Error message
process still running
What it means
After a sync_exec watch action streams the exec session to completion, Compose inspects the exec to fetch its exit code. If ExecInspect still reports Running=true at that point, the exec process never terminated, which would leave the sync step in an ambiguous state, so it errors with 'process still running'.
Source
Thrown at pkg/compose/watch.go:515
Detach: false,
})
if err != nil {
return err
}
// although the errgroup is not tied directly to the context, the operations
// in it are reading/writing to the connection, which is tied to the context,
// so they won't block indefinitely
if err := eg.Wait(); err != nil {
return err
}
execResult, err := t.s.apiClient().ExecInspect(ctx, execCreateResp.ID, client.ExecInspectOptions{})
if err != nil {
return err
}
if execResult.Running {
return errors.New("process still running")
}
if execResult.ExitCode != 0 {
return fmt.Errorf("exit code %d", execResult.ExitCode)
}
return nil
}
func (t tarDockerClient) Untar(ctx context.Context, id string, archive io.ReadCloser) error {
_, err := t.s.apiClient().CopyToContainer(ctx, id, client.CopyToContainerOptions{
DestinationPath: "/",
Content: archive,
CopyUIDGID: true,
})
return err
}
//nolint:gocyclo
func (s *composeService) handleWatchBatch(ctx context.Context, project *types.Project, options api.WatchOptions, batch []watch.FileEvent, rules []watchRule, syncer sync.Syncer) error {View on GitHub (pinned to ddc4b044b6)
Solutions
- Make the sync_exec command finite: ensure it runs to completion and exits (no servers, no tail -f)
- Background or daemonize inside the container yourself if you need a long-running process, and let the exec command return immediately
- If it looks like a transient race, simply retry the watch — the container state is not corrupted
Example fix
# before
- action: sync_exec
path: ./src
target: /app
exec:
command: npm run dev # never exits
# after
- action: sync_exec
path: ./src
target: /app
exec:
command: sh -c "npm install && npm run build" Defensive patterns
Strategy: retry
Validate before calling
docker compose exec <svc> sh -c 'command -v my-one-shot-cmd >/dev/null && my-one-shot-cmd --check'
Try / catch
# transient race retry: re-running watch re-runs sync_exec for i in 1 2 3; do docker compose watch & sleep 5; kill %1 2>/dev/null; done
Prevention
- Keep sync_exec commands strictly finite (build, lint, test) — never servers
- Long-running processes belong in the service entrypoint, not sync_exec
When it happens
Trigger: A develop.watch rule with action: sync_exec whose command is long-running or daemonizing (e.g. a server, tail -f, or a script that backgrounds itself), so the attach streams finish but the exec stays alive.
Common situations: Using sync_exec to run build/test commands that spawn daemons; commands like `npm run dev` that never exit; a race where a slow-starting process has not exited when inspected.
Related errors
- can't watch with action %q on service %s without a command
- exit code %d
- no available sync implementation
- watch rules MUST define a path
- interactive exec is not supported in dry-run mode
AI-assisted analysis of docker/compose@ddc4b044b6 (2026-08-15).
Data as JSON: /api/errors/33e42fd768c07a15.
Report an issue: GitHub.