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
- Delete the PapiPullKey row from config_items so Pull reinitializes from scratch
- Inspect the stored value and correct it to a valid RFC3339 timestamp
- 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
- Never hand-edit config_items rows
- Back up the DB before upgrades/downgrades
- Verify stored timestamps parse as RFC3339 after version changes
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
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- failed to serialize last timestamp: %w
- no header in message, skipping
- no source user in header message, skipping
- unable to parse time
- errUnauthorized
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/45b8d3d1c423f201.
Report an issue: GitHub.