{"record":{"id":"a6fde7866f1d98c9","repo":"juanfont/headscale","slug":"getting-container-logs-w","errorCode":null,"errorMessage":"getting container logs: %w","messagePattern":"getting container logs: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/hi/docker.go","lineNumber":329,"sourceCode":"\n\thostConfig := &container.HostConfig{\n\t\tAutoRemove: false, // We'll remove manually for better control\n\t\tBinds:      binds,\n\t\tMounts:     mounts,\n\t}\n\n\treturn cli.ContainerCreate(ctx, containerConfig, hostConfig, nil, nil, containerName)\n}\n\n// streamAndWait streams container output and waits for completion.\nfunc streamAndWait(ctx context.Context, cli *client.Client, containerID string) (int, error) {\n\tout, err := cli.ContainerLogs(ctx, containerID, container.LogsOptions{\n\t\tShowStdout: true,\n\t\tShowStderr: true,\n\t\tFollow:     true,\n\t})\n\tif err != nil {\n\t\treturn -1, fmt.Errorf(\"getting container logs: %w\", err)\n\t}\n\tdefer out.Close()\n\n\tgo func() {\n\t\t_, _ = io.Copy(os.Stdout, out)\n\t}()\n\n\tstatusCh, errCh := cli.ContainerWait(ctx, containerID, container.WaitConditionNotRunning)\n\tselect {\n\tcase err := <-errCh:\n\t\tif err != nil {\n\t\t\treturn -1, fmt.Errorf(\"waiting for container: %w\", err)\n\t\t}\n\tcase status := <-statusCh:\n\t\treturn int(status.StatusCode), nil\n\t}\n\n\treturn -1, ErrUnexpectedContainerWait","sourceCodeStart":311,"sourceCodeEnd":347,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/cmd/hi/docker.go#L311-L347","documentation":"Returned by `streamAndWait` when `cli.ContainerLogs` fails to attach to the container's output streams before waiting. With Follow:true the attach is a long-lived connection, so this fails on daemon connection issues or if the container vanished between create/start and attach. The function returns exitCode -1, so the real exit status is unknown.","triggerScenarios":"Daemon connection drops at attach time; the container was force-removed right after start; API version mismatch between client and daemon on the logs endpoint; context already cancelled/expired.","commonSituations":"Docker daemon restart or socket replacement mid-run; concurrent cleanup deleting the container; aggressive context timeouts wrapping `runDockerTest`.","solutions":["Verify the container still exists: `docker ps -a | grep hs-`.","Check daemon stability (`docker info`, journalctl for dockerd).","Ensure no parallel cleanup job removes containers during the run.","Retrying the run from scratch is safe — this is a pre-streaming failure."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// confirm the container is still present just before streaming\nif _, err := cli.ContainerInspect(ctx, containerID); err != nil {\n    return fmt.Errorf(\"container vanished before streaming: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if err := runDockerTest(ctx, config); err != nil {\n    if strings.Contains(err.Error(), \"getting container logs\") {\n        // attach-stage failure: verify daemon and container, re-run from scratch\n    }\n}","preventionTips":["Don't force-remove test containers while their run is streaming.","Ensure the docker socket/connection is stable for the whole run.","Keep attach-friendly daemon versions (avoid daemon/client skew)."],"tags":["docker","container-logs","streaming","hi-runner"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}