{"record":{"id":"0b27a2e7da532029","repo":"juanfont/headscale","slug":"reading-container-logs-w","errorCode":null,"errorMessage":"reading container logs: %w","messagePattern":"reading container logs: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"integration/hsic/hsic.go","lineNumber":727,"sourceCode":"\t\t_ = t.pool.Purge(t.pgContainer)\n\t}\n\n\treturn stdoutPath, stderrPath, t.pool.Purge(t.container)\n}\n\n// WriteLogs writes the current stdout/stderr log of the container to\n// the given [io.Writer]s.\nfunc (t *HeadscaleInContainer) WriteLogs(stdout, stderr io.Writer) error {\n\treturn dockertestutil.WriteLog(t.pool, t.container, stdout, stderr)\n}\n\n// ReadLog returns the current stdout and stderr logs from the headscale container.\nfunc (t *HeadscaleInContainer) ReadLog() (string, string, error) {\n\tvar stdout, stderr bytes.Buffer\n\n\terr := dockertestutil.WriteLog(t.pool, t.container, &stdout, &stderr)\n\tif err != nil {\n\t\treturn \"\", \"\", fmt.Errorf(\"reading container logs: %w\", err)\n\t}\n\n\treturn stdout.String(), stderr.String(), nil\n}\n\n// SaveLog saves the current stdout log of the container to a path\n// on the host system.\nfunc (t *HeadscaleInContainer) SaveLog(path string) (string, string, error) {\n\treturn dockertestutil.SaveLog(t.pool, t.container, path)\n}\n\nfunc (t *HeadscaleInContainer) SaveMetrics(savePath string) error {\n\treq, err := http.NewRequestWithContext(context.Background(), http.MethodGet, \"http://\"+net.JoinHostPort(t.hostname, \"9090\")+\"/metrics\", nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating metrics request: %w\", err)\n\t}\n\n\tresp, err := http.DefaultClient.Do(req)","sourceCodeStart":709,"sourceCodeEnd":745,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/integration/hsic/hsic.go#L709-L745","documentation":"Returned by HeadscaleInContainer.ReadLog when the underlying Docker API call to stream the headscale container's stdout/stderr logs fails. It wraps the error from dockertestutil.WriteLog, which executes a log-retrieval request against the Docker daemon. This is a test-harness error, not a headscale server error.","triggerScenarios":"Calling scenario headscale.ReadLog() (typically in test cleanup or failure handlers) when the container has already been purged/stopped, the Docker daemon connection is broken, or the container runtime returned an error streaming logs.","commonSituations":"Calling ReadLog after TearDown/Shutdown has purged the container; Docker daemon restarted mid-test; test-suite container removed by a concurrent run or `hi cleanup`; dockertest pool timeouts.","solutions":["Check that the container is still running before reading logs (call ReadLog before Shutdown/TearDown)","Run `go run ./cmd/hi doctor` and `go run ./cmd/hi cleanup` to remove stale containers/networks from previous runs","Verify the Docker daemon is responsive (`docker ps`) and that no concurrent integration run is purging shared resources","Treat the error as non-fatal in cleanup paths: log it and continue, since the test verdict rarely depends on log retrieval"],"exampleFix":"// before\nstdout, stderr, err := headscale.ReadLog()\nif err != nil {\n    t.Fatalf(\"failed to read logs: %s\", err)\n}\n\n// after (log-collection is best-effort during cleanup)\nstdout, stderr, err := headscale.ReadLog()\nif err != nil {\n    t.Logf(\"could not read container logs: %s\", err)\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"stdout, stderr, err := headscale.ReadLog()\nif err != nil {\n    // log collection is diagnostic only; never fail the test verdict on it\n    t.Logf(\"headscale logs unavailable: %v\", err)\n    stdout, stderr = \"\", \"\"\n}","preventionTips":["Always collect logs before calling Shutdown/TearDown/purge","Treat log retrieval as best-effort in cleanup helpers","Run `hi cleanup` between runs so stale containers don't confuse log lookups"],"tags":["docker","integration-test","logging","container"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}