Skill 104 · Resolving Ingestion Warnings
Subchapter 104.2
references/fixing-cannot-merge-already-identified.mdMarkdown4 KBView on GitHub
An $identify or $create_alias call asked PostHog to merge two persons that are both already identified.
PostHog refuses this to protect identity data — merging two established users is destructive and almost always a bug.
Category merge, severity warning: no data was lost, but the merge did not happen and events continue accumulating under two separate persons.
The SDK call succeeds (2xx) — identify/alias never reports the refusal back.
The only signals are this warning and the symptom: one human, two person profiles, analytics split between them (funnels break, unique-user counts inflate).
identify(user_id) links it to an anonymous session.identify is for linking an anonymous person to a user — exactly once per sign-up/log-in.alias is for attaching an additional ID to a person before or at identification.posthog:execute-sql: SELECT timestamp, details FROM system.ingestion_warnings WHERE type = 'cannot_merge_already_identified' AND timestamp > now() - INTERVAL 7 DAY ORDER BY timestamp DESC LIMIT 20. In the details JSON, each entry carries sourcePersonDistinctId and targetPersonDistinctId — the two sides of the refused merge — plus the event_uuid of the triggering call.posthog:persons-list) and look at their properties and event history.identify() called on account switching or impersonation with a different user’s ID while the device still carries the previous identified session — missing reset() on logout is the classic version.identify/alias — application code cannot join two identified persons, by design.identify with $anon_distinct_id set to another user’s known distinct ID.Fix the identification flow — don’t look for a way to force the merge from application code:
identify only at login/signup, always with the canonical user ID.reset() on logout, especially on shared devices — the next login must start from a fresh anonymous session.identify call, across all platforms and the backend.alias only to attach secondary IDs before the person is identified.identify/alias — it can never work, and the silent refusal makes it look like it does.If two persons genuinely are the same human and must be joined, that is a manual, one-off administrative operation — performed deliberately by a human (and irreversibly joining both event histories) — never something application code does on its own. Confirm both profiles really are the same person before considering it.
system.ingestion_warnings with posthog:execute-sql (filter type = 'cannot_merge_already_identified', timestamp after your fix) — no new occurrences for those distinct IDs.undefined; often the same broken identify callsite produces both.