{"record":{"id":"29d4155eeb60a35f","repo":"juanfont/headscale","slug":"creating-user-w","errorCode":null,"errorMessage":"creating user: %w","messagePattern":"creating user: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/dev/main.go","lineNumber":166,"sourceCode":"\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)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"waiting for headscale: %w\", err)\n\t}\n\n\t// Create user.\n\tfmt.Println(\"Creating user and pre-auth key...\")\n\n\tuserJSON, err := runHS(ctx, hsBin, configPath, \"users\", \"create\", \"dev\", \"-o\", \"json\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating user: %w\", err)\n\t}\n\n\tuserID, err := extractUserID(userJSON)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parsing user: %w\", err)\n\t}\n\n\t// Create pre-auth key.\n\tkeyJSON, err := runHS(\n\t\tctx, hsBin, configPath,\n\t\t\"preauthkeys\", \"create\",\n\t\t\"-u\", strconv.FormatUint(userID, 10),\n\t\t\"--reusable\",\n\t\t\"-e\", \"24h\",\n\t\t\"-o\", \"json\",\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating pre-auth key: %w\", err)","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/cmd/dev/main.go#L148-L184","documentation":"\"creating user: %w\" at cmd/dev/main.go:166 wraps runHS(ctx, hsBin, configPath, \"users\", \"create\", \"dev\", \"-o\", \"json\") in cmd/dev. After the server is healthy, the tool creates a user named 'dev' via the headscale CLI embedded in the just-built binary; failure is either the CLI exiting non-zero (invalid name, DB error) or the command failing to run. CLI stderr/stdout surface the underlying cause.","triggerScenarios":"A user 'dev' already exists (CLI reports duplicate); the server's SQLite database path is unwritable; the CLI subprocess was killed by ctx cancellation; the built binary misbehaves relative to the current config schema.","commonSituations":"Re-running cmd/dev against a persistent state directory where 'dev' was already created; leftover state from a previous run if -keep was used.","solutions":["Delete the existing user first: `<hsBin> -c <config> users delete dev`, or point the dev state dir at a fresh location","Check the CLI output above the error for the exact refusal (duplicate user, DB lock) and address it","Run without -keep so the whole scratch state (including the DB) is recreated each time"],"exampleFix":"# before\n# stale state: user 'dev' already exists from a prior -keep run\n\n# after\nheadscale -c /tmp/headscale-dev-*/config.yaml users delete dev\n# or simply drop the old state dir and re-run: go run ./cmd/dev","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"userJSON, err := runHS(ctx, hsBin, configPath, \"users\", \"create\", \"dev\", \"-o\", \"json\")\nif err != nil {\n\tif strings.Contains(err.Error(), \"already exists\") {\n\t\t// reuse or delete the existing 'dev' user, then continue\n\t}\n\treturn fmt.Errorf(\"creating user: %w\", err)\n}","preventionTips":["Run cmd/dev without -keep so state (including users) is fresh each time","Delete the 'dev' user before re-running against persistent state"],"tags":["dev-tooling","cli","users","provisioning"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}