crowdsecurity/crowdsec · error

loading token: %w

Error message

loading token: %w

What it means

LoadAPICToken reads the stored CAPI JWT from the config-items table via GetConfigItem. If that read fails (database-level error, not an empty token), this wrapped error is returned. A missing/empty token returns ErrTokenNotFound instead, and later steps can return ErrTokenParse/ErrTokenExpired.

Source

Thrown at pkg/database/token.go:32

var (
	ErrTokenNotFound     = errors.New("token not found in DB")
	ErrTokenParse        = errors.New("unable to parse token")
	ErrTokenMissingClaim = errors.New("token missing required claim")
	ErrTokenExpired      = errors.New("token expired")
)

type APICToken struct {
	Raw       string
	ExpiresAt time.Time
}

// LoadAPICToken attempts to retrieve and validate a JWT token from the local database.
// Errors are returned if the token can't be read, is not valid, expired or has no expiration.
func (c *Client) LoadAPICToken(ctx context.Context, logger logrus.FieldLogger) (APICToken, error) {
	token, err := c.GetConfigItem(ctx, APICTokenKey) // TokenKey is a constant string representing the key for the token in the database
	if err != nil {
		return APICToken{}, fmt.Errorf("loading token: %w", err)
	}

	if token == "" {
		return APICToken{}, ErrTokenNotFound
	}

	parser := new(jwt.Parser)

	tok, _, err := parser.ParseUnverified(token, jwt.MapClaims{})
	if err != nil {
		return APICToken{}, fmt.Errorf("%w: %s", ErrTokenParse, err)
	}

	claims, ok := tok.Claims.(jwt.MapClaims)
	if !ok {
		return APICToken{}, ErrTokenParse
	}

View on GitHub (pinned to 909b515798)

Solutions

  1. Check logs for the underlying GetConfigItem error (the %w chain contains the raw DB error).
  2. Fix DB file permissions/ownership for the crowdsec process.
  3. If the DB is corrupt, restore it or re-register ('cscli capi register') which re-creates the token via SaveAPICToken.
  4. If it turns out the token is merely absent/invalid, re-authenticate: 'cscli capi register' + login to get a fresh JWT.

Example fix

// caller: distinguish DB failure from token problems
tok, err := c.LoadAPICToken(ctx, log)
switch {
case errors.Is(err, database.ErrTokenNotFound), errors.Is(err, database.ErrTokenExpired):
    // re-authenticate, normal path
    return authenticate(ctx)
case err != nil:
    return fmt.Errorf("token storage unreadable: %w", err) // real DB problem
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before loading, confirm the DB is reachable
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

Try / catch

tok, err := client.LoadAPICToken(ctx, log)
switch {
case errors.Is(err, database.ErrTokenNotFound),
     errors.Is(err, database.ErrTokenParse),
     errors.Is(err, database.ErrTokenExpired),
     errors.Is(err, database.ErrTokenMissingClaim):
    return reauthenticate(ctx) // expected paths: get a fresh token
case err != nil:
    return fmt.Errorf("token storage unreadable: %w", err) // DB-level problem
}

Prevention

When it happens

Trigger: Calling LoadAPICToken (from Authenticate) when GetConfigItem fails: unreadable or locked SQLite DB, corrupted config-items table, disk I/O error, canceled context.

Common situations: Permissions changed on crowdsec.db during backup/restore; SQLite locked by a long-running cscli command; DB corruption after disk failure.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/e2a3fcc27de3f142. Report an issue: GitHub.