fish2018/pansou · critical
secret cannot be empty
Error message
secret cannot be empty
What it means
Sentinel validation error in GenerateToken (util/jwt.go:22): it fires when the caller passes an empty string as the JWT signing secret, so no token can be signed. It is a guard against misconfiguration, not a crypto failure; the caller (LoginHandler) should supply the configured secret before calling.
Solutions
- Set the JWT secret in configuration/env before the server starts
- Fail fast at startup if the secret is empty rather than at first login
- Check that config loading actually populates the secret key used by LoginHandler
Example fix
// before
token, err := util.GenerateToken(username, cfg.JWTSecret, expiry)
// after
if cfg.JWTSecret == "" {
log.Fatal("JWT secret is not configured")
}
token, err := util.GenerateToken(username, cfg.JWTSecret, expiry) Defensive patterns
Strategy: validation
Validate before calling
if os.Getenv("JWT_SECRET") == "" { log.Fatal("JWT_SECRET not set") } Try / catch
token, err := util.GenerateToken(username, secret, expiry)
if err != nil { log.Fatalf("token signing failed: %v", err) } Prevention
- Fail fast at startup when the secret is missing
- Load the secret before starting the HTTP server
- Never commit empty/default secrets
When it happens
Trigger: 部署时未配置或错误传入空的 JWT 密钥(如配置文件缺失、环境变量为空),用户调用登录接口触发 token 生成。
Common situations: JWT_SECRET env var unset; config file lacks the secret field; secret loaded after this call; empty default in config struct.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/9e36e9c95dbbf98d.
Report an issue: GitHub.
Appendix: source
Thrown at util/jwt.go:22
"errors"
"time"
"github.com/golang-jwt/jwt/v5"
)
// Claims JWT载荷结构
type Claims struct {
Username string `json:"username"`
jwt.RegisteredClaims
}
// GenerateToken 生成JWT token
func GenerateToken(username string, secret string, expiry time.Duration) (string, error) {
if username == "" {
return "", errors.New("username cannot be empty")
}
if secret == "" {
return "", errors.New("secret cannot be empty")
}
expirationTime := time.Now().Add(expiry)
claims := &Claims{
Username: username,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(expirationTime),
IssuedAt: jwt.NewNumericDate(time.Now()),
Issuer: "pansou",
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString([]byte(secret))
}
// ValidateToken 验证JWT token
func ValidateToken(tokenString string, secret string) (*Claims, error) {View on GitHub (pinned to beaa561337)