henrygd/beszel · error

container inspect request failed: %s

Error message

container inspect request failed: %s

What it means

getPodmanContainerHealth talks to the Podman/Docker-compatible REST socket to inspect a container and read its State.Health.Status. This error is thrown when the inspect HTTP request returns a non-200 status; the actual status text (e.g. '404 Not Found') is embedded in the message. It means the health data could not be fetched, not that the container is unhealthy.

Source

Thrown at agent/docker.go:464

// parseDockerHealthStatus maps Docker health status strings to container.DockerHealth values
func parseDockerHealthStatus(status string) (container.DockerHealth, bool) {
	health, ok := container.DockerHealthStrings[strings.ToLower(strings.TrimSpace(status))]
	return health, ok
}

// getPodmanContainerHealth fetches container health status from the container inspect endpoint.
// Used for Podman which doesn't provide health status in the /containers/json endpoint as of March 2026.
// https://github.com/containers/podman/issues/27786
func (dm *dockerManager) getPodmanContainerHealth(containerID string) (container.DockerHealth, error) {
	resp, err := dm.client.Get(fmt.Sprintf("http://localhost/containers/%s/json", url.PathEscape(containerID)))
	if err != nil {
		return container.DockerHealthNone, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return container.DockerHealthNone, fmt.Errorf("container inspect request failed: %s", resp.Status)
	}

	var inspectInfo struct {
		State struct {
			Health struct {
				Status string
			}
		}
	}
	if err := json.NewDecoder(resp.Body).Decode(&inspectInfo); err != nil {
		return container.DockerHealthNone, err
	}

	if health, ok := parseDockerHealthStatus(inspectInfo.State.Health.Status); ok {
		return health, nil
	}

	return container.DockerHealthNone, nil

View on GitHub (pinned to b38fb7dafa)

Solutions

  1. Verify the container ID/name actually exists on the socket being queried (podman ps)
  2. Check socket permissions and that the agent user can access it (groups, SOCK_DIR env)
  3. Confirm the DOCKER_HOST/PODMAN socket URL is correct and the daemon is running
  4. Retry after transient daemon restarts; the stats loop will pick up health on the next tick

Example fix

// before: ambiguous handling of any failure
health, err := getPodmanContainerHealth(ctr)
// after: distinguish missing container from real errors
health, err := getPodmanContainerHealth(ctr)
if err != nil && strings.Contains(err.Error(), "404") {
    health = container.DockerHealthNone // container gone
} else if err != nil {
    log.Warn("podman health check", err)
}
Defensive patterns

Strategy: fallback

Validate before calling

// before relying on health, confirm the container exists on the socket
resp, err := http.Get(sockBase + "/containers/" + id + "/json")
if err != nil || resp.StatusCode != http.StatusOK {
    // skip health for this container
}

Try / catch

health, err := getPodmanContainerHealth(id)
if err != nil {
    log.Warn("health unavailable", "err", err)
    health = container.DockerHealthNone
}

Prevention

When it happens

Trigger: The HTTP GET of the container inspect endpoint (e.g. /containers/{id}/json via the Podman socket) returns any status other than 200 — typically 404 when the container ID does not exist on that socket, 403/401 when the socket denies access, or 500 from the daemon.

Common situations: Agent pointed at a Podman socket but the container was removed/restarted with a new ID; containers running under a different user's podman socket (rootless); insufficient permissions on /run/podman/podman.sock; API version mismatch returning an unexpected status.

Related errors


AI-assisted analysis of henrygd/beszel@b38fb7dafa (2026-08-31). Data as JSON: /api/errors/4f74b4e0e9ded47b. Report an issue: GitHub.