GoogleContainerTools/skaffold · warning
unable to remove container: %w
Error message
unable to remove container: %w
What it means
localDaemon.Remove calls apiClient.ContainerRemove to delete a container by id. On failure it logs a debug line and returns "unable to remove container: %w" with the daemon error preserved. This is used during skaffold cleanup of port-forward or debug containers.
Source
Thrown at pkg/skaffold/docker/image.go:777
}
func (l *localDaemon) Stop(ctx context.Context, id string, stopTimeout *time.Duration) error {
var so client.ContainerStopOptions
if stopTimeout != nil {
so.Timeout = util.Ptr[int](int(stopTimeout.Seconds()))
}
if _, err := l.apiClient.ContainerStop(ctx, id, so); err != nil {
log.Entry(ctx).Debugf("unable to stop running container: %s", err.Error())
return err
}
return nil
}
func (l *localDaemon) Remove(ctx context.Context, id string) error {
if _, err := l.apiClient.ContainerRemove(ctx, id, client.ContainerRemoveOptions{}); err != nil {
log.Entry(ctx).Debugf("unable to remove container: %s", err.Error())
return fmt.Errorf("unable to remove container: %w", err)
}
return nil
}
View on GitHub (pinned to a1189de023)
Solutions
- Treat 'no such container' as success — check if errdefs.IsNotFound and ignore, since the goal state is already met.
- Pass client.ContainerRemoveOptions{Force: true} to remove running containers.
- Verify the container id is current (`docker ps -a`) — stale ids from previous runs fail.
- Check `docker info` if the daemon itself seems down.
Example fix
// before
client.ContainerRemoveOptions{}
// after
client.ContainerRemoveOptions{Force: true, RemoveVolumes: true} Defensive patterns
Strategy: try-catch
Type guard
func isNotFound(err error) bool { var nf errdefs.NotFoundError; return errors.As(err, &nf) || strings.Contains(err.Error(), "No such container") } Try / catch
err := daemon.Remove(ctx, id)
if err != nil {
if isNotFound(err) { return nil } // already gone — desired end state
if strings.Contains(err.Error(), "unable to remove container") { return fmt.Errorf("container %s: force remove or check daemon: %w", id, err) }
return err
} Prevention
- Ignore not-found errors on cleanup paths — idempotent removal is the goal.
- Use Force:true when containers may still be running.
- Refresh container ids each run instead of persisting them.
- Confirm daemon health before batch cleanup operations.
When it happens
Trigger: Calling Remove(ctx, id) when ContainerRemove fails: no such container (already removed), the container is running without a force option (conflict), or the daemon is unreachable.
Common situations: Container already exited and auto-removed (race with --rm), attempting cleanup of a still-running container without Force, stale container id from a previous session, Docker daemon restarting during cleanup.
Related errors
- %q running container image %q errored during run with status
- %q running container image %q timed out after : %v
- pruning removed container: %w
- cannot call Run with empty container config
- pruning images: %w
AI-assisted analysis of GoogleContainerTools/skaffold@a1189de023 (2026-09-05).
Data as JSON: /api/errors/258e6be75ac864f0.
Report an issue: GitHub.