crowdsecurity/crowdsec · error · QueryFail
latest decision id: %w
Error message
latest decision id: %w
What it means
Returned by Client.LatestDecisionID when the query fetching the max decision ID fails (a genuine 'not found' yields 0,nil instead). It wraps the QueryFail sentinel ("unable to query"); the driver error is logged as 'LatestDecisionID : <err>'.
Source
Thrown at pkg/database/decisions.go:69
return []*ent.Decision{}, fmt.Errorf("get all decisions with filters: %w", QueryFail)
}
return data, nil
}
func (c *Client) LatestDecisionID(ctx context.Context) (int, error) {
latest, err := c.Ent.Decision.Query().
Select(decision.FieldID).
Order(ent.Desc(decision.FieldID)).
First(ctx)
if err != nil {
if ent.IsNotFound(err) {
return 0, nil
}
c.Log.Warningf("LatestDecisionID : %s", err)
return 0, fmt.Errorf("latest decision id: %w", QueryFail)
}
return latest.ID, nil
}
func (c *Client) QueryExpiredDecisionsWithFilters(ctx context.Context, now time.Time, filter map[string][]string) ([]*ent.Decision, error) {
query := c.Ent.Decision.Query().
Select(decision.FieldID, decision.FieldUntil, decision.FieldScenario, decision.FieldScope, decision.FieldValue, decision.FieldType, decision.FieldOrigin, decision.FieldUUID).
Where(
decision.UntilLT(now),
)
// Allow a bouncer to ask for non-deduplicated results
if v, ok := filter["dedup"]; !ok || v[0] != "false" {
query = query.Where(longestDecisionForScopeTypeValue)
}
query, err := applyDecisionFilter(query, filter)
if err != nil {View on GitHub (pinned to 909b515798)
Solutions
- Check LAPI logs for the 'LatestDecisionID :' warning to identify the driver error
- If LAPI starts before the DB, add a healthcheck/startup dependency (docker-compose depends_on: condition: service_healthy)
- Verify DB connectivity with the credentials in crowdsec's db config (`cscli db status` equivalent / direct client connect)
- Restore write permissions on the SQLite file/mount if it is read-only
Example fix
// docker-compose before
services:
crowdsec:
image: crowdsecurity/crowdsec
// after
services:
db:
image: mariadb
healthcheck: {test: ["CMD", "healthcheck.sh"], interval: 5s}
crowdsec:
image: crowdsecurity/crowdsec
depends_on:
db: {condition: service_healthy} Defensive patterns
Strategy: try-catch
Validate before calling
// before polling, verify DB reachability
if err := sqlDB.Ping(); err != nil { log.Fatalf("database unreachable: %v", err) } Try / catch
id, err := client.LatestDecisionID(ctx)
if err != nil {
// sentinel wraps 'unable to query'; inspect LAPI log 'LatestDecisionID :'
log.Warnf("latest decision id unavailable, falling back to full pull: %v", err)
id = 0 // forces full stream sync
} Prevention
- Add a DB startup dependency/healthcheck so LAPI never starts before the DB
- Treat 0,nil (not found) and this error differently — only the error means a real DB problem
- Use the stream client's built-in retry instead of polling on failure
When it happens
Trigger: The last-ID SELECT fails due to DB unavailability — connection refused/timeout to MySQL/PostgreSQL, SQLite lock, missing decisions table, or driver error. Called by StreamDecision (stream pulling) and TestLatestDecisionID.
Common situations: LAPI starts before the database container is ready (docker-compose ordering), so every stream request fails with this until DB is up; SQLite file on a read-only mount after restore.
Understand the failure class
Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.
Related errors
- machine not found
- get all decisions with filters: %w
- get expired decisions with filters: %w
- query decision failed: %w
- expired decisions with filters: %w
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/721d392814961855.
Report an issue: GitHub.