crowdsecurity/crowdsec · error
saving token
Error message
saving token: %w
What it means
SaveAPICToken stores the CAPI JWT under APICTokenKey in the config-items table via SetConfigItem. If that write fails, this wrapped error is returned. The token will not be persisted, so subsequent runs will fall back to ErrTokenNotFound on LoadAPICToken.
Solutions
- Check the wrapped error for the DB cause (locked / disk full / read-only).
- Free disk space and ensure the data directory is writable by the crowdsec user.
- Resolve concurrent DB writers or enable WAL mode.
- Retry the authentication flow — without a saved token every CAPI call will re-login until the write succeeds.
Example fix
// before
if err := c.SaveAPICToken(ctx, token); err != nil { return err }
// after: retry transient write failures
if err := c.SaveAPICToken(ctx, token); err != nil {
if errors.Is(err, os.ErrPermission) || strings.Contains(err.Error(), "readonly") {
return fmt.Errorf("cannot persist CAPI token, check /var/lib/crowdsec: %w", err)
}
return fmt.Errorf("saving CAPI token: %w", err)
} Defensive patterns
Strategy: retry
Validate before calling
// pre-check storage before saving the token
if fi, err := os.Stat(dataDir); err != nil || !fi.IsDir() { return fmt.Errorf("data dir missing: %s", dataDir) }
if f, err := os.CreateTemp(dataDir, ".wtest"); err != nil { return err } else { f.Close(); os.Remove(f.Name()) } Try / catch
err := client.SaveAPICToken(ctx, token)
if err != nil {
log.Warnf("could not persist CAPI token, re-login will be required: %v", err)
return fmt.Errorf("token persistence: %w", err)
} Prevention
- Ensure /var/lib/crowdsec is writable and has free space for the crowdsec user.
- Avoid long-held DB locks from concurrent cscli commands during login flows.
- Retry token saves; without persistence every run re-authenticates.
- Watch for read-only remounts after maintenance windows.
When it happens
Trigger: Calling SaveAPICToken (after CAPI login/register) when SetConfigItem fails: SQLite write lock held by another process, disk full, read-only filesystem, corrupted DB, canceled context.
Common situations: Disk quota exhausted in /var/lib/crowdsec; DB locked by a long cscli operation during automated login; read-only mount after a maintenance window.
Related errors
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/8fc633e373260d1b.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/database/token.go:67
}
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}, nil
}
// SaveAPICToken stores the given JWT token in the local database under the appropriate config item.
func (c *Client) SaveAPICToken(ctx context.Context, token string) error {
if err := c.SetConfigItem(ctx, APICTokenKey, token); err != nil {
return fmt.Errorf("saving token: %w", err)
}
return nil
}
View on GitHub (pinned to 909b515798)