Intercom "Update contacts" destination: 409 conflict race when concurrent invocations create the same new contact
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 39.9k
- Forks
- 3.4k
- Avg merge
- 6h 51m
- Merged PRs (30d)
- 232
Description
Bug Description
What happens
The Intercom contacts destination (built from the official template) fails with http_4xx when two invocations for the same person run near-simultaneously and the contact doesn't exist in Intercom yet:
Error from intercom api (status 409): {'type': 'error.list', 'errors': [{'code': 'conflict', 'message': 'A contact matching those details already exists with id=...'}]}
Why it happens
The template does search-by-email → create-if-not-found. For a brand-new user, $identify and a $set-carrying event (e.g. sign_up, login, $screen) often arrive within the same few seconds. Both invocations search, both find nothing, both POST a create — the second one gets the 409 and the invocation is marked FAILED. Verified in our project (EU Cloud): within 10s of an $identify, the same users routinely fire multiple $set-carrying events, so any destination matching both Identify and Set person properties races on every new contact.
Expected behavior
The template should treat 409 as "contact exists": parse the id from the error body and retry as an update (PUT /contacts/{id}), i.e. behave as an upsert. Alternatively, use Intercom's upsert semantics where available.
Impact
Every new contact produces failed invocations that pollute error monitoring; data self-heals on the next event but the noise makes real failures hard to spot. Currently working around it by forking the source code, which detaches us from template updates.
Environment
- PostHog EU Cloud
- Destination: Intercom — Update contacts (official template, OAuth connection)
- Reproducible: consistently, on any contact new to Intercom with two matched events within a few seconds
Debug info
- [ ] PostHog Cloud, Debug information: [please copy/paste from https://us.posthog.com/settings/project-details#variables or https://eu.posthog.com/settings/project-details#variables]
- [ ] PostHog Hobby self-hosted with `docker compose`, version/commit: [please provide]
- [ ] PostHog self-hosted with Kubernetes (deprecated, see [`Sunsetting Kubernetes support`](https://posthog.com/blog/sunsetting-helm-support-posthog)), version/commit: [please provide]
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at the official Intercom contacts destination template and trace the search-by-email, create-if-not-found path described in the report. Reproduce concurrent identify and $set-carrying events for a new contact; done means a create race treats the 409 response as an existing contact, updates it, and no longer marks the invocation failed, with a regression test for the race.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100