AdguardTeam/AdGuardHome · error

userid: %w

Error message

userid: %w

What it means

Create rejected a user record because its UserID is the zero value; the wrapped sentinel is errors.ErrEmptyValue. The in-memory user database requires every created user to have a non-empty identifier.

Source

Thrown at internal/aghuser/db.go:132

func (db *DefaultDB) ByUUID(ctx context.Context, id UserID) (u *User, err error) {
	db.mu.Lock()
	defer db.mu.Unlock()

	u, ok := db.userIDToUser[id]
	if !ok {
		return nil, nil
	}

	return u, nil
}

// Create implements the [DB] interface for *DefaultDB.
func (db *DefaultDB) Create(ctx context.Context, u *User) (err error) {
	db.mu.Lock()
	defer db.mu.Unlock()

	if u.ID == (UserID{}) {
		return fmt.Errorf("userid: %w", errors.ErrEmptyValue)
	}

	_, ok := db.userIDToUser[u.ID]
	if ok {
		return fmt.Errorf("userid: %w", errors.ErrDuplicated)
	}

	_, ok = db.loginToUserID[u.Login]
	if ok {
		return fmt.Errorf("login: %w", errors.ErrDuplicated)
	}

	db.userIDToUser[u.ID] = u
	db.loginToUserID[u.Login] = u.ID

	return nil
}

View on GitHub (pinned to b41aefbe51)

Solutions

  1. Generate an ID before calling Create, e.g. u.ID = aghuser.NewUserID()
  2. If importing users, map each source user to a fresh UserID
  3. Add a lint/test that asserts u.ID != UserID{} before persistence

Example fix

// before
err := db.Create(ctx, &aghuser.User{Login: "alice"})
// after
u := &aghuser.User{Login: "alice"}
u.ID = aghuser.NewUserID()
err := db.Create(ctx, u)
Defensive patterns

Strategy: validation

Validate before calling

if u.ID == (aghuser.UserID{}) {
    u.ID = aghuser.NewUserID()
}

Type guard

func hasUserID(u *aghuser.User) bool { return u.ID != aghuser.UserID{} }

Try / catch

if err := db.Create(ctx, u); err != nil {
    if errors.Is(err, errors.ErrEmptyValue) { u.ID = aghuser.NewUserID(); err = db.Create(ctx, u) }
}

Prevention

When it happens

Trigger: Calling DefaultDB.Create with a User whose ID field was never set (u.ID == UserID{}), typically when the caller expects the DB to autogenerate IDs — it does not.

Common situations: Building users from parsed config or requests without generating an ID first; refactors that dropped the ID assignment; test fixtures forgetting to set an ID.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


AI-assisted analysis of AdguardTeam/AdGuardHome@b41aefbe51 (2026-08-27). Data as JSON: /api/errors/e03d933663dd4b17. Report an issue: GitHub.