goauthentik / goauthentik/authentik

LDAP Sync attempts to recreate already-linked users and fails with duplicate username constraint

Open
#22,803 0 comments 3 reactions 2 assignees Claimed by @gergosimonyi View on GitHub
bug
Dominant language
Python
Stars
25.6k
Forks
2k
Avg merge
1d 2h
Merged PRs (30d)
659

Description

### Describe the bug

We are experiencing repeated LDAP synchronization errors where Authentik attempts to create users that already exist and are already linked to the LDAP source.

During LDAP sync, Authentik raises the following error:

```text
Failed to create user: duplicate key value violates unique constraint "authentik_core_user_username_key"
DETAIL: Key (username)=() already exists.
```

The notification suggests connecting the user via the LDAP Source's "Synced Users" tab, however the affected users are already correctly linked to the LDAP source.

## LDAP Source configuration

- Source type: LDAP
- LDAP server: Microsoft Active Directory
- Object uniqueness field:

```text
objectSid
```

- User mapping uses standard Authentik mappings
- Username mapping:

```python
return {
"username": ldap.get("sAMAccountName"),
}
```

No custom username transformations are configured.

## Error details

Example stack trace:

```text
/authentik/sources/ldap/sync/users.py
line 111
sync()

django.db.models.query.create()

IntegrityError:
duplicate key value violates unique constraint
"authentik_core_user_username_key"

DETAIL:
Key (username)=(user_a) already exists.
```

The same happens for multiple users during every synchronization run.

Example log entry:

```json
{
"action": "configuration_error",
"context": {
"dn": "CN=User A,OU=Department,DC=example,DC=com",
"message": "Failed to create user; To merge new user with existing user, connect it via the LDAP Source's 'Synced Users' tab."
}
}
```

## What we verified

For each affected user:

### User exists

```sql
SELECT id, username
FROM authentik_core_user
WHERE username = 'user_a';
```

Result:

```text
1 row returned
```

### LDAP SID stored in user attributes

```sql
SELECT attributes->>'ldap_uniq'
FROM authentik_core_user
WHERE username = 'user_a';
```

Result:

```text
S-1-5-21-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxx
```

### Source connection exists

```sql
SELECT *
FROM authentik_core_usersourceconnection
WHERE user_id = ;
```

Result:

```text
1 row returned
```

### LDAP source connection exists

```sql
SELECT *
FROM authentik_sources_ldap_userldapsourceconnection
WHERE usersourceconnection_ptr_id = ;
```

Result:

```text
1 row returned
```

### SID matches connection identifier

```sql
SELECT
u.attributes->>'ldap_uniq' as attr_sid,
c.identifier as connection_sid
FROM authentik_core_user u
JOIN authentik_core_usersourceconnection c
ON c.user_id = u.id
WHERE username = 'user_a';
```

Result:

```text
attr_sid == connection_sid
```

### LDAP object exists and is unique

LDAP query:

```bash
ldapsearch \
'(sAMAccountName=user_a)' \
objectSid
```

Result:

```text
Exactly one LDAP entry returned
```

No duplicate LDAP objects exist.

### No duplicate usernames in Authentik

```sql
SELECT lower(username), COUNT(*)
FROM authentik_core_user
GROUP BY lower(username)
HAVING COUNT(*) > 1;
```

Result:

```text
0 rows
```

### No duplicate ldap_uniq values

```sql
SELECT
attributes->>'ldap_uniq',
COUNT(*)
FROM authentik_core_user
WHERE attributes ? 'ldap_uniq'
GROUP BY attributes->>'ldap_uniq'
HAVING COUNT(*) > 1;
```

Result:

```text
0 rows
```

## Example affected users (anonymized)

| Username | LDAP linked | Source connection | LDAP source connection |
|-----------|-------------|------------------|------------------------|
| user_a | Yes | Yes | Yes |
| user_b | Yes | Yes | Yes |
| user_c | Yes | Yes | Yes |
| user_d | Yes | Yes | Yes |
| user_e | Yes | Yes | Yes |

Verification query:

```sql
SELECT
u.username,
u.attributes->>'ldap_uniq' AS attr_sid,
c.identifier AS conn_sid,
c.id AS conn_id,
l.usersourceconnection_ptr_id AS ldap_conn_id
FROM authentik_core_user u
LEFT JOIN authentik_core_usersourceconnection c
ON c.user_id = u.id
LEFT JOIN authentik_sources_ldap_userldapsourceconnection l
ON l.usersourceconnection_ptr_id = c.id
WHERE u.username IN ('user_a','user_b','user_c','user_d','user_e');
```

Result:

```text
All users have:
- attr_sid = conn_sid
- valid usersourceconnection
- valid ldap_userldapsourceconnection
```

All affected users also have:

```text
path = goauthentik.io/sources//...
```

indicating they were originally created by the LDAP source.

## Additional observation

We also discovered some users that have an LDAP path but no source connection:

```text
LDAP-path users: 2084
Source connections: 1884
LDAP connections: 1884
```

However, the users generating the duplicate username errors are **not among those orphaned users**. The affected users already have valid source and LDAP connections.

## Actual behavior

Authentik executes a user creation path (`create()` in `users.py`) for users that are already linked to the LDAP source, resulting in a database uniqueness violation on `username`.

## Questions

- Is this a known issue in 2026.5.2?
- Are there any known conditions that could cause LDAP sync to ignore an existing `UserSourceConnection` and attempt a fresh user creation?
- Is there any recommended way to rebuild LDAP synchronization metadata for already-linked users without deleting and recreating them?

### How to reproduce

Don't know how to reproduce. It happens with a small number of users and everything seems ok with those users

### Expected behavior

During synchronization, Authentik should detect the existing linked user and update it instead of attempting to create a new user.

### Screenshots

_No response_

### Additional context

_No response_

### Deployment Method

Docker

### Version

2026.5.2

### Relevant log output

```shell

```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.