docker/cli · error
cannot attach to a restarting container, wait until it is…
Error message
cannot attach to a restarting container, wait until it is running
What it means
inspectContainerAndCheckState returns errors.New("cannot attach to a restarting container, wait until it is running") at line 37 when c.Container.State.Restarting is true. During a restart policy triggered cycle the container is transitional (not yet Running), so attach is rejected; the caller should wait for the container to reach a stable running state.
Solutions
- Wait for the container to reach Running: `docker wait` is not suitable here; poll `docker inspect -f '{{.State.Running}}' <id>` until true, or use `until docker inspect -f '{{.State.Status}}' id | grep -q running; do ...`.
- If it crash-loops, inspect `docker logs <id>` and fix the crash cause (entrypoint, missing config).
- Temporarily remove/loosen the restart policy to inspect, or `docker update --restart=no <id>`.
Example fix
# before (container mid-restart)
docker attach web
# after — wait for running then attach
until [ "$(docker inspect -f '{{.State.Running}}' web)" = "true" ]; do sleep 1; done
docker attach web Defensive patterns
Strategy: validation
Validate before calling
c, err := cli.Client().ContainerInspect(ctx, id, client.ContainerInspectOptions{})
if err != nil { return err }
if c.State.Restarting {
// wait for Running: poll or back off
return fmt.Errorf("container %s is restarting; retry shortly", id)
} Try / catch
for attempt := 0; attempt < maxRetry; attempt++ {
if _, err := inspectContainerAndCheckState(ctx, cli.Client(), id); err == nil { break }
if !strings.Contains(err.Error(), "restarting container") { return err }
// brief wait, then retry (use a timer, not a busy loop)
} Prevention
- For crash-looping containers, inspect `docker logs` to fix the root cause first.
- Consider `docker update --restart=no` to stop the restart cycle while debugging.
- Poll State.Running before attach rather than attaching blindly.
When it happens
Trigger: Running `docker attach <id>` against a container with a restart policy (e.g. --restart=always/unless-stopped/on-failure) that is currently mid-restart — the process exited and the daemon is restarting it.
Common situations: Containers that crash-loop with a restart policy; attaching immediately after a host/daemon restart; flapping services; attaching during a restart-policy backoff window.
Related errors
- cannot attach to a stopped container, start it first
- cannot attach to a paused container, unpause it first
- source can not be empty
- destination can not be empty
- must specify at least one container source
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/d35c1cf1e7f2bb8d.
Report an issue: GitHub.
Appendix: source
Thrown at cli/command/container/attach.go:37
type AttachOptions struct {
NoStdin bool
Proxy bool
DetachKeys string
}
func inspectContainerAndCheckState(ctx context.Context, apiClient client.APIClient, args string) (*container.InspectResponse, error) {
c, err := apiClient.ContainerInspect(ctx, args, client.ContainerInspectOptions{})
if err != nil {
return nil, err
}
if !c.Container.State.Running {
return nil, errors.New("cannot attach to a stopped container, start it first")
}
if c.Container.State.Paused {
return nil, errors.New("cannot attach to a paused container, unpause it first")
}
if c.Container.State.Restarting {
return nil, errors.New("cannot attach to a restarting container, wait until it is running")
}
return &c.Container, nil
}
// newAttachCommand creates a new cobra.Command for `docker attach`
func newAttachCommand(dockerCLI command.Cli) *cobra.Command {
var opts AttachOptions
cmd := &cobra.Command{
Use: "attach [OPTIONS] CONTAINER",
Short: "Attach local standard input, output, and error streams to a running container",
Args: cli.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
containerID := args[0]
return RunAttach(cmd.Context(), dockerCLI, containerID, &opts)
},
Annotations: map[string]string{View on GitHub (pinned to 4f84911bfe)