Tencent/WeKnora · critical
failed to generate JWT secret: %v
Error message
failed to generate JWT secret: %v
What it means
This panic occurs during lazy JWT secret initialization in the user service. After checking the JWT_SECRET env var, the code falls back to crypto/rand to generate 32 random bytes; if the OS entropy source fails, it panics with the wrapped error. It is an intentionally fatal startup failure because a JWT secret is mandatory for signing tokens.
Source
Thrown at internal/application/service/user.go:89
// Machine-readable change-password failure reasons for HTTP details fields.
const (
DetailInvalidOldPassword = "invalid_old_password"
DetailPasswordPolicy = "password_policy"
DetailSamePassword = "same_password"
)
// getJwtSecret retrieves the JWT secret from the environment, falling back to a securely generated random secret.
func getJwtSecret() string {
jwtSecretOnce.Do(func() {
if envSecret := strings.TrimSpace(os.Getenv("JWT_SECRET")); envSecret != "" {
jwtSecret = envSecret
return
}
randomBytes := make([]byte, 32)
if _, err := rand.Read(randomBytes); err != nil {
panic(fmt.Sprintf("failed to generate JWT secret: %v", err))
}
jwtSecret = base64.StdEncoding.EncodeToString(randomBytes)
})
return jwtSecret
}
// userService implements the UserService interface
type userService struct {
userRepo interfaces.UserRepository
tokenRepo interfaces.AuthTokenRepository
tenantService interfaces.TenantService
memberService interfaces.TenantMemberService
config *config.Config
systemSettingSvc interfaces.SystemSettingService
}
// NewUserService creates a new user service instanceView on GitHub (pinned to 988cbb0330)
Solutions
- Set the JWT_SECRET environment variable so the rand fallback is never taken
- Fix the runtime environment: update the container/seccomp profile to allow the getrandom syscall, or ensure /dev/urandom is available
- Retry process startup; rand.Read failure is usually transient on early boot
- Replace with a deterministic secret source (key file/KMS) if the platform cannot supply entropy
Example fix
// before jwtSecret = envSecret // after export JWT_SECRET=$(openssl rand -base64 32) # in deployment env, avoids rand fallback entirely
Defensive patterns
Strategy: fallback
Validate before calling
secret := os.Getenv("JWT_SECRET")
if secret == "" {
if _, err := rand.Read(make([]byte, 32)); err != nil {
return nil, fmt.Errorf("entropy unavailable: %w", err)
}
} Type guard
func hasJWTSecret() bool { return strings.TrimSpace(os.Getenv("JWT_SECRET")) != "" } Try / catch
func jwtSecretSafe() (s string, err error) {
defer func() { if r := recover(); r != nil { err = fmt.Errorf("jwt secret init panicked: %v", r) } }()
return getJWTSecret(), nil
} Prevention
- Always set JWT_SECRET in every deployment environment
- Allow getrandom in container seccomp profiles
- Provision secrets from a secret manager rather than runtime generation
- Fail health checks early if entropy is unavailable
When it happens
Trigger: First call to the JWT-secret singleton when JWT_SECRET is unset/empty and rand.Read on the 32-byte slice returns an error (e.g. getrandom(2) syscall failure, exhausted or blocked entropy source, restricted seccomp/sandbox blocking getrandom).
Common situations: Containers with constrained /dev/urandom or seccomp profiles that block the getrandom syscall; exotic OSes or minimal kernels lacking getrandom; early-boot environments where the random device is not yet ready.
Related errors
- failed to generate OIDC state signing key: %v
- im: duplicate command registration: %s
- api-key policy declared for non-existent route(s): %s
- types.TenantIDContextKey not set in context
- failed to generate schema: %v
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/b62530e10142117d.
Report an issue: GitHub.