GoogleContainerTools/skaffold · error
pruning removed container: %w
Error message
pruning removed container: %w
What it means
localDaemon.Delete removes a container and then prunes to clean up, returning "pruning removed container: %w" if apiClient.ContainerPrune fails. Note the container removal itself only logs a warning; it is the prune step that surfaces as a hard error. This wraps daemon/transport failures during the prune API call.
Source
Thrown at pkg/skaffold/docker/image.go:223
}
}
func (l *localDaemon) ContainerExists(ctx context.Context, name string) bool {
_, err := l.apiClient.ContainerInspect(ctx, name, client.ContainerInspectOptions{})
return err == nil
}
// Delete stops, removes, and prunes a running container
func (l *localDaemon) Delete(ctx context.Context, out io.Writer, id string) error {
if _, err := l.apiClient.ContainerStop(ctx, id, client.ContainerStopOptions{}); err != nil {
log.Entry(ctx).Debugf("unable to stop running container: %s", err.Error())
}
if _, err := l.apiClient.ContainerRemove(ctx, id, client.ContainerRemoveOptions{}); err != nil {
log.Entry(ctx).Warnf("unable to remove container: %s", err.Error())
}
_, err := l.apiClient.ContainerPrune(ctx, client.ContainerPruneOptions{})
if err != nil {
return fmt.Errorf("pruning removed container: %w", err)
}
return nil
}
// Run creates a container from a given image reference, and returns a wait channel and the container ID.
func (l *localDaemon) Run(ctx context.Context, out io.Writer, opts ContainerCreateOpts) (<-chan container.WaitResponse, <-chan error, string, error) {
if opts.ContainerConfig == nil {
return nil, nil, "", fmt.Errorf("cannot call Run with empty container config")
}
c, err := l.apiClient.ContainerCreate(ctx, client.ContainerCreateOptions{
Config: opts.ContainerConfig,
HostConfig: &container.HostConfig{
NetworkMode: container.NetworkMode(opts.Network),
VolumesFrom: opts.VolumesFrom,
PortBindings: opts.Bindings,
Mounts: opts.Mounts,
},
Name: opts.Name,View on GitHub (pinned to a1189de023)
Solutions
- Verify the daemon is healthy with `docker info`; restart Docker Desktop/daemon if it is wedged, then retry the delete.
- Check the context/deadline: rerun without cancellation or increase timeout if the prune timed out.
- For remote DOCKER_HOST, confirm connectivity (ssh tunnel / tcp port) and retry.
- Treat as cleanup-best-effort: confirm the container itself is gone (`docker ps -a`); the prune failure usually only affects reclaiming stopped containers/networks.
Example fix
// before: delete fails at prune when daemon is restarting
if _, err := l.apiClient.ContainerPrune(ctx, client.ContainerPruneOptions{}); err != nil {
return fmt.Errorf("pruning removed container: %w", err)
}
// after (caller-side resilience): log prune failure instead of failing cleanup
if _, err := l.apiClient.ContainerPrune(ctx, client.ContainerPruneOptions{}); err != nil {
log.Entry(ctx).Warnf("unable to prune after container removal: %s", err.Error())
}
return nil Defensive patterns
Strategy: try-catch
Validate before calling
// Go: check daemon reachability before Delete cleanup
cli, _ := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if _, err := cli.Ping(context.Background()); err != nil {
log.Warnf("docker daemon unreachable, skipping container cleanup: %v", err)
return nil
} Try / catch
if err := daemon.Delete(ctx, id); err != nil {
// cleanup is best-effort: the container may already be removed
if strings.Contains(err.Error(), "pruning removed container") {
log.Warnf("post-removal prune failed (container itself likely gone): %v", err)
return nil
}
return err
} Prevention
- Avoid restarting Docker Desktop while skaffold dev is running; stop the session first.
- Increase client timeouts for remote DOCKER_HOST connections.
- Treat delete/prune errors as warnings in teardown paths.
- Monitor daemon health (`docker info`) before long dev sessions.
When it happens
Trigger: Calling Delete(ctx, id) (the LocalDaemon interface method) when ContainerPrune returns an error: Docker daemon stopped/restarting mid-call, context cancelled or timed out, daemon returned 500, or network connection to a remote DOCKER_HOST dropped during the prune request.
Common situations: Skaffold dev cleanup while Docker Desktop is restarting; long-running prune hitting the daemon's request timeout; remote Docker (ssh/tcp DOCKER_HOST) connection reset; daemon disk pressure causing prune API failure.
Related errors
- pruning images: %w
- StatusCode_BUILD_DOCKER_GET_DIGEST_ERR
- docker build: %w
- loading image into docker daemon: %w
- unable to remove container: %w
AI-assisted analysis of GoogleContainerTools/skaffold@a1189de023 (2026-09-05).
Data as JSON: /api/errors/c2a5bcffd505a5f3.
Report an issue: GitHub.