crowdsecurity/crowdsec · error

saving token: %w

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.

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)

Solutions

  1. Check the wrapped error for the DB cause (locked / disk full / read-only).
  2. Free disk space and ensure the data directory is writable by the crowdsec user.
  3. Resolve concurrent DB writers or enable WAL mode.
  4. 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

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.