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

  1. Set the JWT secret in configuration/env before the server starts
  2. Fail fast at startup if the secret is empty rather than at first login
  3. 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

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)