crowdsecurity/crowdsec · error

failed to parse last timestamp: %w

Error message

failed to parse last timestamp: %w

What it means

Pull reads the previously stored last-pull timestamp from the database and parses it with UnmarshalText. This error means the stored PapiPullKey value is not a valid RFC3339 text timestamp, so pulling cannot resume from the saved position.

Source

Thrown at pkg/apiserver/papi.go:261

	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()

	p.Logger.Debugf("current subscription type is %s", currentSubscriptionType)

	if currentSubscriptionType == apiclient.SubscriptionTypeEnterprise || currentSubscriptionType == apiclient.SubscriptionTypeSecOps {
		// If allowed to use PAPI, start it
		// Otherwise it will be started when the token is refreshed with an ent subscription
		p.Logger.Infof("Starting PAPI pull (since:%s)", lastTimestamp)
		papiChan = p.Client.Start(papiCtx, lastTimestamp)
	}

View on GitHub (pinned to 909b515798)

Solutions

  1. Delete the PapiPullKey row from config_items so Pull reinitializes from scratch
  2. Inspect the stored value and correct it to a valid RFC3339 timestamp
  3. Confirm no other tooling is writing to config_items

Example fix

// before (manually corrupted value in DB)
UPDATE config_items SET value='yesterday' WHERE name='papi_pull_last';
// after
DELETE FROM config_items WHERE name='papi_pull_last';
Defensive patterns

Strategy: validation

Validate before calling

if v := db.GetConfigItem(PapiPullKey); v != "" { if _, err := time.Parse(time.RFC3339, v); err != nil { /* delete or repair the item */ } }

Try / catch

if err := p.Pull(ctx); err != nil { if strings.Contains(err.Error(), "failed to parse last timestamp") { /* reset PapiPullKey and retry pull */ } }

Prevention

When it happens

Trigger: lastTimestampStr is non-empty but UnmarshalText fails — the config item in the database was manually edited, written by an incompatible version, or corrupted.

Common situations: Manual DB manipulation of config_items, downgrade/upgrade across versions with changed storage format, partial write from a crashed run.

Understand the failure class

Related errors


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