{"record":{"id":"bd94e630fbed9ae9","repo":"crowdsecurity/crowdsec","slug":"updating-machine-last-heartbeat-w-w","errorCode":null,"errorMessage":"updating machine last_heartbeat: %w: %w","messagePattern":"updating machine last_heartbeat: %w: %w","errorType":"exception","errorClass":"UpdateFail","httpStatus":null,"severity":"error","filePath":"pkg/database/machines.go","lineNumber":195,"sourceCode":"\nfunc (c *Client) BulkDeleteWatchers(ctx context.Context, machines []*ent.Machine) (int, error) {\n\tids := make([]int, len(machines))\n\tfor i, b := range machines {\n\t\tids[i] = b.ID\n\t}\n\n\tnbDeleted, err := c.Ent.Machine.Delete().Where(machine.IDIn(ids...)).Exec(ctx)\n\tif err != nil {\n\t\treturn nbDeleted, err\n\t}\n\n\treturn nbDeleted, nil\n}\n\nfunc (c *Client) UpdateMachineLastHeartBeat(ctx context.Context, machineID string) error {\n\t_, err := c.Ent.Machine.Update().Where(machine.MachineIdEQ(machineID)).SetLastHeartbeat(time.Now().UTC()).Save(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"updating machine last_heartbeat: %w: %w\", err, UpdateFail)\n\t}\n\n\treturn nil\n}\n\nfunc (c *Client) UpdateMachineScenarios(ctx context.Context, scenarios string, id int) error {\n\t_, err := c.Ent.Machine.UpdateOneID(id).\n\t\tSetUpdatedAt(time.Now().UTC()).\n\t\tSetScenarios(scenarios).\n\t\tSave(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to update machine in database: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (c *Client) UpdateMachineIP(ctx context.Context, ipAddr string, id int) error {","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/database/machines.go#L177-L213","documentation":"UpdateMachineLastHeartBeat wraps UpdateFail when setting last_heartbeat on a machine row fails. The heartbeat endpoint calls this on every watcher ping, so an error here means the DB rejected the write while a watcher was alive. Watchers will see their heartbeat request fail (usually surfaced as a 500/4xx by HandleDBErrors).","triggerScenarios":"HeartBeat -> UpdateMachineLastHeartBeat with the DB down or the UPDATE failing: SQLite locked, connection pool exhausted, DB restart mid-request, disk full.","commonSituations":"Many watchers heartbeating at once overloading a slow SQLite file; DB maintenance/restart window; container OOM-killing the DB; wrong db_config after host migration.","solutions":["Check the wrapped error to identify the SQL cause","Confirm the DB is healthy: `cscli machines list` from the same host","Under sustained heartbeat load on SQLite, switch db_config to MySQL/Postgres","Restart LAPI to rebuild DB connection pools after a DB restart","Monitor disk space on the machine hosting the DB"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// check machine resolvable before heartbeat persistence\nif _, err := db.QueryMachineByID(ctx, machineID); err != nil { return err }","typeGuard":null,"tryCatchPattern":"if err := db.UpdateMachineLastHeartBeat(ctx, machineID); err != nil {\n    if errors.Is(err, database.UpdateFail) {\n        // transient DB issue: return 503 to watcher so it retries heartbeat\n    }\n    return err\n}","preventionTips":["Heartbeats are frequent: use a DB that sustains write rate (Postgres/MySQL for many watchers)","Set DB connection pool sizes appropriately in db_config","Monitor DB restarts/maintenance and expect transient heartbeat failures","Keep DB host disk usage monitored"],"tags":["database","update-failed","heartbeat","crowdsec"],"backgroundTag":"database-write-failed","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}