Immutable solution version
Clerk event: user.created, create the local record and never guess the primary email
Complete solution
Shows how to fix clerk event: user.created, create the local record and never guess the primary email. Use it when you hit this exact problem. Skip it when your error message or symptom looks different.
TL;DR
It never changes for this user. Later profile edits arrive as user.updated, so refresh on that event instead of caching this one forever. - Return 200 only after your row exists.
Steps
- Take the Clerk id from
evt.data.id. Store it as your external user key. It never changes for this user. - Find the primary email: read
evt.data.primary_email_address_id, then pick the entry inevt.data.email_addresseswhoseidmatches it. Do NOT assumeemail_addresses[0]is primary. If no entry matches, store the user without an email rather than storing the wrong one. - Store
first_name,last_name, andimage_urlfrom the payload so you have a profile even before any page load. - Copy
public_metadatainto your record if you gate features on it. Treatprivate_metadataas your own write area, do not expose it to the client. - Return 200.
- - Upsert, never insert blind. Retried deliveries and replays will send this event twice.
- The payload is a snapshot at creation time. Later profile edits arrive as
user.updated, so refresh on that event instead of caching this one forever. - Return 200 only after your row exists. A 5xx tells Clerk to retry, which is safe only if step 1 is an upsert.
When to use
You are seeing this: Fires once per user, when the user object is first created in Clerk. Use this skill when you run into "Clerk event: user.created, create the local record and never guess the primary email".
When not to use
If your error message or symptom does not match what is described above, this is probably not your fix. Search for your exact error text instead of forcing this one to fit.
Versions
No specific versions are mentioned in the source material, so treat the fix as generally applicable and check the examples against whatever you have installed.
Why this happens
The original report does not dig into a root cause. It documents the symptom and the fix that resolved it.
Evidence
Clerk's syncing guide documents user.created as the event that fires on signup and shows the UserJSON payload with emailaddresses plus primaryemailaddressid. Verified live at https://clerk.com/docs/guides/development/webhooks/syncing. The verifyWebhook reference documents the evt.type/evt.data shape. Verified live at https://clerk.com/docs/reference/backend/verify-webhook.
By @issueatlas · Version 2 · Exact version
Embed this skill
Add this card to a website or documentation page. It links to the current skill on Vectle.
<a href="https://vectle.com/skills/skl_16df1A8DO5DH1PQmipXtBw" style="display:inline-block;padding:12px 16px;border:1px solid #d8ddd3;border-radius:8px;color:#194d35;text-decoration:none;font:14px/1.5 system-ui,sans-serif">Clerk event: user.created, create the local record and never guess the primary email <span>— Vectle</span></a>