{"record":{"id":"b08d05d1e63cca35","repo":"crowdsecurity/crowdsec","slug":"user-s-w","errorCode":null,"errorMessage":"user '%s': %w","messagePattern":"user '(.+?)': %w","errorType":"exception","errorClass":"UserExists","httpStatus":null,"severity":"warning","filePath":"pkg/database/machines.go","lineNumber":98,"sourceCode":"\t}\n\n\tif len(machineExist) > 0 {\n\t\tif force {\n\t\t\t_, err := c.Ent.Machine.Update().Where(machine.MachineIdEQ(*machineID)).SetPassword(string(hashPassword)).Save(ctx)\n\t\t\tif err != nil {\n\t\t\t\tc.Log.Warningf(\"CreateMachine : %s\", err)\n\t\t\t\treturn nil, fmt.Errorf(\"machine '%s': %w\", *machineID, UpdateFail)\n\t\t\t}\n\n\t\t\tmachine, err := c.QueryMachineByID(ctx, *machineID)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"machine '%s': %w: %w\", *machineID, err, QueryFail)\n\t\t\t}\n\n\t\t\treturn machine, nil\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"user '%s': %w\", *machineID, UserExists)\n\t}\n\n\tmachine, err := c.Ent.Machine.\n\t\tCreate().\n\t\tSetMachineId(*machineID).\n\t\tSetPassword(string(hashPassword)).\n\t\tSetIpAddress(ipAddress).\n\t\tSetIsValidated(isValidated).\n\t\tSetAuthType(authType).\n\t\tSave(ctx)\n\tif err != nil {\n\t\tc.Log.Warningf(\"CreateMachine : %s\", err)\n\t\treturn nil, fmt.Errorf(\"creating machine '%s': %w\", *machineID, InsertFail)\n\t}\n\n\treturn machine, nil\n}\n","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/database/machines.go#L80-L116","documentation":"CreateMachine wraps the sentinel UserExists (errors.New(\"user already exists\")) when it is asked to register a machine whose machineId is already stored in the machines table. It is raised only after an initial lookup found an existing row, so it means a duplicate registration, not a DB failure. Callers should check with errors.Is(err, UserExists).","triggerScenarios":"Calling Client.CreateMachine with a machineID that already exists in the database; via LAPI 'register' / 'add machine' endpoints when the watcher name is taken; re-running machine enrollment for an already-enrolled watcher.","commonSituations":"Re-running `cscli machines add <name>` for an existing machine; two watchers configured with the same machine_id; re-running test setup (registerFlushTestMachine) against a non-flushed DB; enrolling the same LAPI credentials from a second agent without validating/overwriting.","solutions":["Check existence first with QueryMachineByID or use errors.Is(err, UserExists) after the call and treat it as idempotent success if appropriate","Delete or rename the existing machine: `cscli machines delete <name>` or pick a unique machine_id","If the intent is to re-register, pass a new password and update the existing row instead of creating a new one","Use `cscli lapi register -u <url> -m <machine_id>` with a unique -m per watcher"],"exampleFix":"// before\nmachine, err := db.CreateMachine(ctx, \"agent-1\", password, ip, true, \"password\")\n// after\nmachine, err := db.CreateMachine(ctx, \"agent-1\", password, ip, true, \"password\")\nif err != nil {\n    if errors.Is(err, database.UserExists) {\n        machine, err = db.QueryMachineByID(ctx, \"agent-1\")\n    }\n    if err != nil { return err }\n}","handlingStrategy":"try-catch","validationCode":"// Go: pre-check before creating\nif _, err := db.QueryMachineByID(ctx, machineID); err == nil {\n    return fmt.Errorf(\"machine %q already registered\", machineID)\n}","typeGuard":null,"tryCatchPattern":"if _, err := db.CreateMachine(ctx, id, pw, ip, valid, auth); err != nil {\n    if errors.Is(err, database.UserExists) {\n        // idempotent path: fetch and reuse the existing machine\n    } else {\n        return err\n    }\n}","preventionTips":["Always branch on errors.Is(err, database.UserExists) rather than string-matching the message","Use unique machine_id per watcher/agent (hostname+uuid)","In tests, flush the DB between registrations (registerFlushTestMachine exists for this)","Prefer update/validate flows over create when re-enrolling an existing watcher"],"tags":["database","duplicate-record","crowdsec","lapi"],"backgroundTag":"record-already-exists","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"}