juanfont/headscale · error
converting private key to string for saving: %w
Error message
converting private key to string for saving: %w
What it means
Returned by readOrCreatePrivateKey when key.NewMachine().MarshalText() fails while persisting a newly generated noise private key (hscontrol/app.go:969). MachinePrivate.MarshalText encodes the key to its textual form; for a valid in-memory key this operation is effectively infallible in tailscale.com/util/key — this error is a defensive guard that essentially never fires in practice.
Source
Thrown at hscontrol/app.go:971
}
func readOrCreatePrivateKey(path string) (*key.MachinePrivate, error) {
dir := filepath.Dir(path)
err := util.EnsureDir(dir)
if err != nil {
return nil, fmt.Errorf("ensuring private key directory: %w", err)
}
privateKey, err := os.ReadFile(path)
if errors.Is(err, os.ErrNotExist) {
log.Info().Str("path", path).Msg("no private key file at path, creating...")
machineKey := key.NewMachine()
machineKeyStr, err := machineKey.MarshalText()
if err != nil {
return nil, fmt.Errorf(
"converting private key to string for saving: %w",
err,
)
}
err = os.WriteFile(path, machineKeyStr, privateKeyFileMode)
if err != nil {
return nil, fmt.Errorf(
"saving private key to disk at path %q: %w",
path,
err,
)
}
return &machineKey, nil
} else if err != nil {
return nil, fmt.Errorf("reading private key file: %w", err)
}View on GitHub (pinned to 565fd254d0)
Solutions
- Rebuild/reinstall headscale from a clean checkout so the vendored tailscale.com/util/key version matches (go mod tidy && make build).
- If maintaining a fork, verify the vendored key package is unmodified.
- Treat as a build-environment problem: clear the module cache (go clean -modcache) and rebuild.
Defensive patterns
Strategy: try-catch
Try / catch
// Practically unreachable; treat any occurrence as a build/library mismatch.
if err := h.Serve(); err != nil && strings.Contains(err.Error(), "converting private key to string") {
log.Fatal().Msg("binary built against incompatible tailscale key package; rebuild cleanly")
} Prevention
- Build from a clean checkout with the repo's pinned toolchain (nix develop && make build).
- Do not fork or patch vendored tailscale.com/util/key.
When it happens
Trigger: Only conceivable if the key type's MarshalText signature gains a failure mode in a future tailscale.com/util/key version (e.g. invalid internal state). No current input, config, or environment triggers it.
Common situations: Virtually none; if it appears, it indicates a corrupted build or an incompatible tailscale library version linked into a custom compile of headscale.
Related errors
- reading or creating Noise protocol private key: %w
- reading or creating DERP server private key: %w
- DERP server private key and noise private key are the same:
- ensuring private key directory: %w
- saving private key to disk at path %q: %w
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/c1cf8b75191fdfc1.
Report an issue: GitHub.