crowdsecurity/crowdsec · warning · UserExists
user '%s': %w
Error message
user '%s': %w
What it means
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).
Source
Thrown at pkg/database/machines.go:98
}
if len(machineExist) > 0 {
if force {
_, err := c.Ent.Machine.Update().Where(machine.MachineIdEQ(*machineID)).SetPassword(string(hashPassword)).Save(ctx)
if err != nil {
c.Log.Warningf("CreateMachine : %s", err)
return nil, fmt.Errorf("machine '%s': %w", *machineID, UpdateFail)
}
machine, err := c.QueryMachineByID(ctx, *machineID)
if err != nil {
return nil, fmt.Errorf("machine '%s': %w: %w", *machineID, err, QueryFail)
}
return machine, nil
}
return nil, fmt.Errorf("user '%s': %w", *machineID, UserExists)
}
machine, err := c.Ent.Machine.
Create().
SetMachineId(*machineID).
SetPassword(string(hashPassword)).
SetIpAddress(ipAddress).
SetIsValidated(isValidated).
SetAuthType(authType).
Save(ctx)
if err != nil {
c.Log.Warningf("CreateMachine : %s", err)
return nil, fmt.Errorf("creating machine '%s': %w", *machineID, InsertFail)
}
return machine, nil
}
View on GitHub (pinned to 909b515798)
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
Example fix
// before
machine, err := db.CreateMachine(ctx, "agent-1", password, ip, true, "password")
// after
machine, err := db.CreateMachine(ctx, "agent-1", password, ip, true, "password")
if err != nil {
if errors.Is(err, database.UserExists) {
machine, err = db.QueryMachineByID(ctx, "agent-1")
}
if err != nil { return err }
} Defensive patterns
Strategy: try-catch
Validate before calling
// Go: pre-check before creating
if _, err := db.QueryMachineByID(ctx, machineID); err == nil {
return fmt.Errorf("machine %q already registered", machineID)
} Try / catch
if _, err := db.CreateMachine(ctx, id, pw, ip, valid, auth); err != nil {
if errors.Is(err, database.UserExists) {
// idempotent path: fetch and reuse the existing machine
} else {
return err
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- machine not found
- get all decisions with filters: %w
- latest decision id: %w
- get expired decisions with filters: %w
- query decision failed: %w
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/b08d05d1e63cca35.
Report an issue: GitHub.