wtfutil/wtf · error
could not get container list: %w
Error message
could not get container list: %w
What it means
getContainerStates calls cli.ContainerList(ctx, container.ListOptions{All: true}); any transport or API failure is stringified as "could not get container list" into the widget buffer. The daemon's /containers/json call did not return a usable list.
Source
Thrown at modules/docker/client.go:113
padSlice(true, sysInfo, func(i int) string {
return sysInfo[i].name
}, func(i int, newVal string) {
sysInfo[i].name = newVal
})
result := ""
for _, info := range sysInfo {
result += fmt.Sprintf("[%s]%s %s\n", widget.settings.labelColor, info.name, info.value)
}
return result
}
func (widget *Widget) getContainerStates() string {
cntrs, err := widget.cli.ContainerList(context.Background(), container.ListOptions{All: true})
if err != nil {
return fmt.Errorf("could not get container list: %w", err).Error()
}
if len(cntrs) == 0 {
return " no containers"
}
colorMap := map[string]string{
"created": "green",
"running": "lime",
"paused": "yellow",
"restarting": "yellow",
"removing": "yellow",
"exited": "red",
"dead": "red",
}
containers := []struct {
name stringView on GitHub (pinned to bb838c1ccb)
Solutions
- Confirm docker ps -a works in the same environment.
- Recreate the Docker client (NewClientWithOpts) if the daemon restarted — cached connections can go stale.
- Fix socket permissions / docker group membership.
- Align client library and daemon versions if the error persists across calls.
Example fix
// before
cntrs, err := widget.cli.ContainerList(context.Background(), container.ListOptions{All: true})
if err != nil {
return fmt.Errorf("could not get container list: %w", err).Error()
}
// after
cntrs, err := widget.cli.ContainerList(context.Background(), container.ListOptions{All: true})
if err != nil {
return fmt.Errorf("could not get container list: %w", err).Error() // consider rebuilding cli on connection errors
} Defensive patterns
Strategy: fallback
Validate before calling
if _, err := widget.cli.Ping(context.Background()); err != nil {
// daemon unreachable — skip ContainerList and show connectivity hint
} Type guard
func isConnectionReset(err error) bool {
return errors.Is(err, io.EOF) || errors.Is(err, syscall.ECONNRESET) || errors.Is(err, context.DeadlineExceeded)
} Try / catch
cntrs, err := widget.cli.ContainerList(ctx, container.ListOptions{All: true})
if err != nil {
if isConnectionReset(err) {
widget.reconnect() // rebuild client after daemon restart
}
widget.displayBuffer = "container list unavailable: " + err.Error()
return
} Prevention
- Ping the daemon before list calls and rebuild the client on stale connections.
- Prevent laptop sleep/suspend of Docker Desktop during long sessions.
- Keep SSH tunnels to remote daemons alive (autossh) when using DOCKER_HOST over SSH.
When it happens
Trigger: cli.ContainerList fails: daemon unreachable (same causes as Info), permission denied on the socket, stale connection after daemon restart, or an invalid All option on a mismatched API version.
Common situations: Docker Desktop sleeping/suspending on laptops, socket permissions after a fresh install, remote daemon behind an SSH tunnel that dropped, API version skew after a Docker upgrade.
Related errors
- could not get docker system info: %w
- failed to execute Azure query: %w
- executing request: %w
- unexpected status %d from DEV.to API
- could not get disk usage: %w
AI-assisted analysis of wtfutil/wtf@bb838c1ccb (2026-09-03).
Data as JSON: /api/errors/c471a39491676b8c.
Report an issue: GitHub.