{"record":{"id":"d05e090580f975a6","repo":"juanfont/headscale","slug":"building-headscale-w","errorCode":null,"errorMessage":"building headscale: %w","messagePattern":"building headscale: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/dev/main.go","lineNumber":138,"sourceCode":"\tif err != nil {\n\t\treturn fmt.Errorf(\"writing config: %w\", err)\n\t}\n\n\t// Build headscale.\n\tfmt.Println(\"Building headscale...\")\n\n\thsBin := filepath.Join(tmpDir, \"headscale\")\n\n\tctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)\n\tdefer stop()\n\n\tbuild := exec.CommandContext(ctx, \"go\", \"build\", \"-o\", hsBin, \"./cmd/headscale\")\n\tbuild.Stdout = os.Stdout\n\tbuild.Stderr = os.Stderr\n\n\terr = build.Run()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"building headscale: %w\", err)\n\t}\n\n\t// Start headscale serve.\n\tfmt.Println(\"Starting headscale server...\")\n\n\tserve := exec.CommandContext(ctx, hsBin, \"serve\", \"-c\", configPath)\n\tserve.Stdout = os.Stdout\n\tserve.Stderr = os.Stderr\n\n\terr = serve.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"starting headscale: %w\", err)\n\t}\n\n\t// Wait for server to be ready.\n\thealthURL := fmt.Sprintf(\"http://127.0.0.1:%d/health\", *port)\n\n\terr = waitForHealth(ctx, healthURL, 30*time.Second)","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/cmd/dev/main.go#L120-L156","documentation":"\"building headscale: %w\" at cmd/dev/main.go:138 wraps build.Run() of `go build -o <tmpDir>/headscale ./cmd/headscale` executed by cmd/dev. The tool compiles the real server binary into the scratch dir before serving; any compile error, missing toolchain, or write failure surfaces here. Stdout/stderr of the go build are already streamed to the console (build.Stdout/Stderr = os.Stdout/os.Stderr), so the actual compiler diagnostics appear above this error.","triggerScenarios":"Running `go run ./cmd/dev` on a tree with compile errors; Go toolchain not installed or older than go.mod's 1.26.1 minimum; GOFLAGS/GOOS misconfigured so the binary is written for the wrong platform; read-only GOCACHE; no write access to the tmpDir.","commonSituations":"Pulling a branch mid-refactor; CI image with an older Go; a stale nix shell (AGENTS.md pins Go 1.26.1 via `nix develop`); GOFLAGS=-mod=vendor without a vendor dir.","solutions":["Read the compiler output printed before the error — fix the reported source lines first","Enter the pinned toolchain: `nix develop` then re-run `go run ./cmd/dev`","Verify `go version` >= 1.26.1 and `go build ./cmd/headscale` succeeds standalone"],"exampleFix":"# before\nsystem go   # old toolchain, fails at go.mod's 1.26.1 minimum\ngo run ./cmd/dev\n\n# after\nnix develop -c go run ./cmd/dev","handlingStrategy":"try-catch","validationCode":"// verify the toolchain compiles before invoking the dev harness\nbuild := exec.Command(\"go\", \"build\", \"./cmd/headscale\")\nif err := build.Run(); err != nil {\n\treturn fmt.Errorf(\"tree does not compile, fix first: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if err := build.Run(); err != nil {\n\t// compiler diagnostics were already streamed; surface exit cause only\n\tif ctx.Err() != nil {\n\t\treturn nil // interrupted build is an expected shutdown\n\t}\n\treturn fmt.Errorf(\"building headscale: %w\", err)\n}","preventionTips":["Run `go build ./...` before `go run ./cmd/dev` on WIP trees","Use `nix develop` for the pinned Go 1.26.1 toolchain","Never run cmd/dev with GOOS/GOARCH overridden for another target"],"tags":["dev-tooling","build","go-toolchain","compile"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}