{"record":{"id":"3e0ba54a91b928b4","repo":"crowdsecurity/crowdsec","slug":"unable-to-read-logs-from-container-s-w","errorCode":null,"errorMessage":"unable to read logs from container %s: %w","messagePattern":"unable to read logs from container (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/acquisition/modules/docker/run.go","lineNumber":626,"sourceCode":"\t\t}\n\n\t\twait := bo.NextBackOff()\n\n\t\tcontainer.logger.Debugf(\"tail failed but container is (presumed) healthy: %v, retrying in %s\", err, wait)\n\n\t\tselect {\n\t\tcase <-time.After(wait):\n\t\tcase <-container.t.Dying():\n\t\t\tcontainer.logger.Infof(\"tail stopped\")\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\nfunc (d *Source) tailContainerAttempt(ctx context.Context, container *ContainerConfig, outChan chan pipeline.Event, bo backoff.BackOff) error {\n\tdockerReader, err := d.Client.ContainerLogs(ctx, container.ID, *container.logOptions)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to read logs from container %s: %w\", container.Name, err)\n\t}\n\n\t// Log connection (both initial and reconnections)\n\tcontainer.logger.Info(\"connected to container logs\")\n\n\t// reset backoff so for the next disconnect, the interval doesn't start from 30sec\n\tbo.Reset()\n\n\tvar scanner *bufio.Scanner\n\t// we use this library to normalize docker API logs (cf. https://ahmet.im/blog/docker-logs-api-binary-format-explained/)\n\tif container.Tty {\n\t\tscanner = bufio.NewScanner(dockerReader)\n\t} else {\n\t\treader := dlog.NewReader(dockerReader)\n\t\tscanner = bufio.NewScanner(reader)\n\t}\n\n\treaderChan := make(chan string)","sourceCodeStart":608,"sourceCodeEnd":644,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/acquisition/modules/docker/run.go#L608-L644","documentation":"tailContainerAttempt opens the container log stream with d.Client.ContainerLogs(ctx, container.ID, *container.logOptions). If that API call fails (daemon unreachable, container gone/removed, API rejected options), it wraps the error as \"unable to read logs from container %s\". It is the initial connection (or reconnection attempt, under backoff) to a container's logs failing.","triggerScenarios":"ContainerLogs called with a container ID that no longer exists (container removed between discovery and tail), docker daemon temporarily down, or a socket-proxy denying the /containers/{id}/logs endpoint; also bad log options (e.g. invalid tail/since values rejected by the daemon).","commonSituations":"Short-lived containers that exit and are removed while crowdsec is starting; docker daemon restart; log driver not supporting reading logs (e.g. \"none\"); socket-proxy blocking the logs route.","solutions":["Confirm the container exists and its log driver supports reading: `docker inspect -f '{{.HostConfig.LogConfig}}' <name>` (avoid \"none\").","Check the docker daemon/socket is reachable and permissions allow the logs API.","With docker-socket-proxy, allow the containers/logs endpoints.","This error is retried via the backoff passed to tailContainerAttempt — leave the source running and it will reconnect when the container/daemon returns."],"exampleFix":"// before (daemon-compose service)\nlogging:\n  driver: none\n// after\nlogging:\n  driver: json-file\n  options:\n    max-size: \"10m\"","handlingStrategy":"retry","validationCode":"// Go: verify the container still exists before tailing\n_, err := cli.ContainerInspect(ctx, container.ID)\nif err != nil {\n\t// container gone; re-resolve by name instead of tailing a stale ID\n\treturn reResolve(ctx, container.Name)\n}","typeGuard":null,"tryCatchPattern":"err := d.tailContainerAttempt(ctx, container, outChan, bo)\nif err != nil && strings.Contains(err.Error(), \"unable to read logs from container\") {\n\td.WaitFor(time.After(bo.NextBackOff())) // backoff retry\n}","preventionTips":["Avoid log driver \"none\" on containers whose logs you must read.","For short-lived containers, prefer event-driven discovery over one-shot reads.","Keep daemon socket local or use a proxy that allows the logs endpoint.","Check container name resolution at startup and log clear warnings."],"tags":["docker","logs","acquisition"],"backgroundTag":"file-read-failed","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}