{"record":{"id":"fb7917ff9add1a28","repo":"juanfont/headscale","slug":"writing-config-w","errorCode":null,"errorMessage":"writing config: %w","messagePattern":"writing config: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/dev/main.go","lineNumber":121,"sourceCode":"\tif err != nil {\n\t\treturn fmt.Errorf(\"creating temp dir: %w\", err)\n\t}\n\n\tif !*keep {\n\t\tdefer os.RemoveAll(tmpDir)\n\t}\n\n\t// Write config.\n\tconfigPath := filepath.Join(tmpDir, \"config.yaml\")\n\tconfigContent := fmt.Sprintf(\n\t\tdevConfig,\n\t\t*port, *port, metricsPort,\n\t\ttmpDir, tmpDir, tmpDir,\n\t)\n\n\terr = os.WriteFile(configPath, []byte(configContent), 0o600)\n\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}","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/cmd/dev/main.go#L103-L139","documentation":"\"writing config: %w\" at cmd/dev/main.go:121 wraps os.WriteFile(configPath, ..., 0o600) in the cmd/dev bootstrapper. After creating the temp dir, the tool renders the devConfig template (ports, metrics port, tmpDir paths) and writes it to <tmpDir>/config.yaml. Failure here is almost always a filesystem-level error on a directory the tool itself just created, or an interrupted run.","triggerScenarios":"Running cmd/dev when the temp dir was removed between MkdirTemp and WriteFile (e.g. aggressive tmp reaper such as systemd-tmpfiles), the filesystem filled up mid-run (ENOSPC), or the process lacks permission in TMPDIR.","commonSituations":"Disk full during development; TMPDIR on a tmpfs with a small size limit; parallel dev runs racing with cleanup tooling.","solutions":["Free space on the filesystem holding TMPDIR (check df -h \"$TMPDIR\") and re-run","Point TMPDIR at a larger, local directory","Re-run the command — transient tmp-reaper interference is cleared by a fresh temp dir"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := os.WriteFile(configPath, []byte(configContent), 0o600); err != nil {\n\tif errors.Is(err, syscall.ENOSPC) {\n\t\t// free space in TMPDIR and retry once with a fresh temp dir\n\t}\n\treturn fmt.Errorf(\"writing config: %w\", err)\n}","preventionTips":["Monitor free space on the temp filesystem during long dev sessions","Avoid tmp-reaper intervals shorter than a dev run"],"tags":["dev-tooling","filesystem","config","environment"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}