crowdsecurity/crowdsec · error

failed to serialize last timestamp: %w

Error message

failed to serialize last timestamp: %w

What it means

Pull serializes the starting timestamp with MarshalText before storing it as the PapiPullKey config item on the first pull. This error means the time.Time value could not be marshaled to text — practically unexpected since time.Time always marshals, so it signals an internal/clock anomaly.

Source

Thrown at pkg/apiserver/papi.go:251

	return nil
}

// Pull is the long polling client for real-time decisions from PAPI
func (p *Papi) Pull(ctx context.Context) error {
	p.Logger.Infof("Starting Polling API Pull")

	lastTimestamp := time.Time{}

	lastTimestampStr, err := p.DBClient.GetConfigItem(ctx, PapiPullKey)
	if err != nil {
		p.Logger.Warningf("failed to get last timestamp for papi pull: %s", err)
	}

	// value doesn't exist, it's first time we're pulling
	if lastTimestampStr == "" {
		binTime, err := lastTimestamp.MarshalText()
		if err != nil {
			return fmt.Errorf("failed to serialize last timestamp: %w", err)
		}

		if err := p.DBClient.SetConfigItem(ctx, PapiPullKey, string(binTime)); err != nil {
			p.Logger.Errorf("error setting papi pull last key: %s", err)
		} else {
			p.Logger.Debugf("config item '%s' set in database with value '%s'", PapiPullKey, string(binTime))
		}
	} else {
		if err := lastTimestamp.UnmarshalText([]byte(lastTimestampStr)); err != nil {
			return fmt.Errorf("failed to parse last timestamp: %w", err)
		}
	}

	tokenRefreshChan := p.apiClient.GetTokenRefreshChan()
	var papiChan chan longpollclient.Event // Chan is nil by default to block until PAPI actually establishes the connection
	papiCtx, cancel := context.WithCancel(ctx)

	currentSubscriptionType := p.apiClient.GetSubscriptionType()

View on GitHub (pinned to 909b515798)

Solutions

  1. Fix the system clock (NTP sync) and restart crowdsec
  2. Delete the stored PapiPullKey config item and let Pull reinitialize
  3. Verify the host/container time configuration
Defensive patterns

Strategy: validation

Validate before calling

if lastTimestamp.Year() < 1 || lastTimestamp.Year() > 9999 { return fmt.Errorf("lastTimestamp out of range: %v", lastTimestamp) }

Try / catch

if err := p.Pull(ctx); err != nil { if strings.Contains(err.Error(), "failed to serialize last timestamp") { log.Error("clock anomaly; check system time"); } }

Prevention

When it happens

Trigger: First-time pull (no stored PapiPullKey value) and lastTimestamp.MarshalText() returns an error, e.g. a time value outside the representable range (year overflow) coming from the system clock.

Common situations: System clock set far in the future or past in a container/VM, corrupted time source, or running with a fabricated time in tests.

Understand the failure class

Background: "JSON serialization failed", "not JSON serializable", "Failed to serialize": why JSON marshaling errors happen and how to fix them — this error's family across 46 libraries.

Related errors


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