juanfont/headscale · error
failed to generate API key
Error message
failed to generate API key
What it means
Sentinel in hscontrol/db/api_key.go returned by CreateAPIKey when generating the key material itself fails. CreateAPIKey builds a 12-char hex prefix and 64-char hex secret via tailscale.com/util/rands and hashes the secret; failure at that stage (essentially only a broken crypto/rand source) aborts creation before the row is persisted.
Source
Thrown at hscontrol/db/api_key.go:27
"github.com/juanfont/headscale/hscontrol/types"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
"tailscale.com/util/rands"
)
const (
apiKeyPrefix = "hskey-api-" //nolint:gosec // This is a prefix, not a credential
apiKeyPrefixLength = 12
apiKeyHashLength = 64
// Legacy format constants.
legacyAPIPrefixLength = 7
legacyAPIKeyLength = 32
)
var (
ErrAPIKeyFailedToParse = errors.New("failed to parse ApiKey")
ErrAPIKeyGenerationFailed = errors.New("failed to generate API key")
ErrAPIKeyExpired = errors.New("API key expired")
)
// CreateAPIKey creates a new [types.APIKey] in a user, and returns it.
func (hsdb *HSDatabase) CreateAPIKey(
expiration *time.Time,
) (string, *types.APIKey, error) {
// Generate public prefix (12 chars)
prefix := rands.HexString(apiKeyPrefixLength)
// Generate secret (64 chars)
secret := rands.HexString(apiKeyHashLength)
// Full key string (shown ONCE to user)
keyStr := apiKeyPrefix + prefix + "-" + secret
// bcrypt hash of secret
hash, err := bcrypt.GenerateFromPassword([]byte(secret), bcrypt.DefaultCost)View on GitHub (pinned to 565fd254d0)
Solutions
- Verify /dev/urandom exists and is readable inside the container/host running headscale
- Retry key creation once — transient entropy starvation is possible early after boot
- If running in a restricted sandbox, expose a working entropy source to the process
Defensive patterns
Strategy: retry
Try / catch
key, ak, err := hsdb.CreateAPIKey(&exp)
if err != nil {
if errors.Is(err, db.ErrAPIKeyGenerationFailed) {
// entropy-source failure: safe to retry once; otherwise surface it
key, ak, err = hsdb.CreateAPIKey(&exp)
}
if err != nil {
return fmt.Errorf("creating API key: %w", err)
}
} Prevention
- Ensure /dev/urandom is available in containers running headscale
- Alert on key-creation failures — they indicate host-level entropy problems
- Do not silently retry in a tight loop; one retry then fail fast
When it happens
Trigger: Calling HSDatabase.CreateAPIKey(expiration) on a host where the system entropy source is unavailable or crypto/rand errors, causing prefix/secret generation to fail. Extremely rare in practice.
Common situations: Stripped-down containers with no /dev/urandom; exotic runtimes (some wasm/sandbox environments) where crypto/rand is not backed by a working entropy device.
Related errors
- failed to parse ApiKey
- node not found
- failed to parse oauth client secret
- failed to parse auth-key
- getting random IP: %w
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/503f0920fe767920.
Report an issue: GitHub.