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

  1. Check existence first with QueryMachineByID or use errors.Is(err, UserExists) after the call and treat it as idempotent success if appropriate
  2. Delete or rename the existing machine: `cscli machines delete <name>` or pick a unique machine_id
  3. If the intent is to re-register, pass a new password and update the existing row instead of creating a new one
  4. 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

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


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/b08d05d1e63cca35. Report an issue: GitHub.