crowdsecurity/crowdsec · error · ErrTokenParse
%w: %s
Error message
%w: %s
What it means
LoadAPICToken calls ParseUnverified to decode the stored CAPI JWT. If the token string cannot be parsed as a JWT (malformed, truncated, not a token at all), the returned error wraps ErrTokenParse with the parser message. This is a data problem in the stored token, not a network or DB connectivity problem.
Source
Thrown at pkg/database/token.go:43
}
// 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
}
expFloat, ok := claims["exp"].(float64)
if !ok {
return APICToken{}, fmt.Errorf("%w: exp", ErrTokenMissingClaim)
}
exp := time.Unix(int64(expFloat), 0)
if time.Now().UTC().After(exp.Add(-1 * time.Minute)) {
return APICToken{}, ErrTokenExpired
}
return APICToken{Raw: token, ExpiresAt: exp}, nilView on GitHub (pinned to 909b515798)
Solutions
- Delete/re-register the token: 'cscli capi delete' then 'cscli capi register', or clear the APICTokenKey config item and re-authenticate to store a fresh JWT.
- Verify the stored value actually looks like a JWT (three dot-separated base64url segments).
- Never hand-edit the token in the database; use cscli commands.
Example fix
// caller: treat parse failure as 'token unusable', force re-auth
tok, err := c.LoadAPICToken(ctx, log)
if errors.Is(err, database.ErrTokenParse) {
log.Warn("stored CAPI token corrupt, re-authenticating")
return authenticate(ctx)
} Defensive patterns
Strategy: try-catch
Validate before calling
// quick structural sanity check on a stored token string before parsing
func looksLikeJWT(tok string) bool {
parts := strings.Split(tok, ".")
return len(parts) == 3 && parts[0] != "" && parts[1] != ""
} Type guard
func isTokenParseErr(err error) bool { return errors.Is(err, database.ErrTokenParse) } Try / catch
tok, err := client.LoadAPICToken(ctx, log)
if isTokenParseErr(err) {
log.Warn("stored CAPI token is corrupt, forcing re-authentication")
return reauthenticate(ctx)
} Prevention
- Never hand-edit or paste tokens into the database.
- Restore DB and config items together from consistent backups.
- Use cscli capi register/login for all token lifecycle changes.
- Validate a restored token's shape before relying on it.
When it happens
Trigger: Calling LoadAPICToken when the config item contains a corrupt or hand-edited token string; a failed/partial SaveAPICToken wrote garbage; an old token format incompatible with the current parser.
Common situations: Manual editing of the DB/config by an operator; restore from an inconsistent backup; upgrade across versions where token generation changed.
Related errors
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/51ef8f6d8654fa3e.
Report an issue: GitHub.