henrygd/beszel · error
logs request failed: %s: %s
Error message
logs request failed: %s: %s
What it means
getLogs requests container logs from the Docker API and streams the response. This error is thrown when the logs endpoint returns a non-200 status; the message carries the HTTP status plus up to 1KB of the daemon's response body. It means no log stream was obtained at all, as opposed to decode/stream errors later in the function.
Source
Thrown at agent/docker.go:872
}
endpoint, err := buildDockerContainerEndpoint(containerID, "logs", query)
if err != nil {
return "", err
}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil)
if err != nil {
return "", err
}
resp, err := dm.client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(io.LimitReader(resp.Body, 1024))
return "", fmt.Errorf("logs request failed: %s: %s", resp.Status, strings.TrimSpace(string(body)))
}
var builder strings.Builder
contentType := resp.Header.Get("Content-Type")
multiplexed := strings.HasSuffix(contentType, "multiplexed-stream")
logReader := io.Reader(resp.Body)
if !multiplexed {
// Podman may return multiplexed logs without Content-Type. Sniff the first frame header
// with a small buffered reader only when the header check fails.
bufferedReader := bufio.NewReaderSize(resp.Body, 8)
multiplexed = detectDockerMultiplexedStream(bufferedReader)
logReader = bufferedReader
}
if err := decodeDockerLogStream(logReader, &builder, multiplexed); err != nil {
return "", err
}
// Strip ANSI escape sequences from logs for clean display in web UIView on GitHub (pinned to b38fb7dafa)
Solutions
- Check status and body in the message — 404 means the container is gone, 400 means bad params
- Ensure stdout=true or stderr=true is set in the log request query
- Refresh the container ID via a new list call before retrying
- Retry transient 5xx with backoff
Example fix
// before: missing stream flags
q := url.Values{}
logs, err := getLogs(id, q)
// after
q := url.Values{}
q.Set("stdout", "true")
q.Set("stderr", "true")
q.Set("tail", "100")
logs, err := getLogs(id, q) Defensive patterns
Strategy: validation
Validate before calling
q := url.Values{}
q.Set("stdout", "true")
q.Set("stderr", "true")
q.Set("tail", "200")
// confirm container exists first
if !containerExists(id) { return } Try / catch
logs, err := getLogs(id, q)
if err != nil {
var statusErr string
if strings.Contains(err.Error(), "404") { statusErr = "gone" }
log.Warn("logs unavailable", "container", id, "reason", statusErr, "err", err)
return
} Prevention
- Always request stdout and/or stderr in log queries
- Validate tail/since parameter formats before sending
- Re-list containers after daemon restarts; handle 404 gracefully
When it happens
Trigger: GET /containers/{id}/logs with query params (tail, stdout, stderr, timestamps) returns non-200: 404 (container missing), 400 (bad query params, e.g. neither stdout nor stderr requested), 403, or 5xx.
Common situations: Requesting logs for a container that just exited/removed; malformed tail/since parameter values; API-proxy stripping required query parameters; daemon restarted between listing and log fetch.
Related errors
- container inspect request failed: %s
- docker version request failed: %s
- container info request failed: %s: %s
- log frame size (%d) exceeds maximum (%d)
- new request: %w
AI-assisted analysis of henrygd/beszel@b38fb7dafa (2026-08-31).
Data as JSON: /api/errors/e3f723da70a6a424.
Report an issue: GitHub.