Python SDK user bulk creation from CSV throwing 409

Stuck on bulk-creating users from a CSV using the Python SDK. I have a loop calling create_user with user_obj, but it fails with 409 Conflict on the second iteration. Is the create_user method synchronous and blocking the next request? I need to handle the rate limiting or use a batch endpoint if available. My current snippet:

for row in csv_reader:
 user_obj = UserBuilder.build_user(row)
 api_response = users_api.create_user(user_obj)

How do I properly sequence these calls without hitting the conflict?

TL;DR: 409 is a duplicate email, not rate limiting.

You might want to look at catching the ApiException with status 409 and skipping that row instead of crashing. The create_user endpoint is strict about unique emails, so check if those users already exist in your org before the loop.

It depends, but generally… skipping the 409 is a band-aid. You’re hitting the duplicate constraint, not rate limits.

409 Conflict: A user with the same email address already exists.

Check existence first or use the bulk import endpoint instead of looping create_user.

If I remember correctly, looping through create_user is a recipe for disaster when migrating from Twilio Studio flows where state is implicit. The suggestion above correctly identifies the 409 as a duplicate email conflict, but you are ignoring the deeper issue: you are not handling the API’s eventual consistency model. When you create a user, the email index update might lag slightly, causing subsequent checks or creates to fail unexpectedly if done too fast. Do not just catch the exception. Use platformClient.users.get_users(email="[email protected]") before creating. If it returns empty, create. If it returns a list, skip or update. Also, add a 100ms sleep between requests. The Python SDK does not auto-throttle. You will hit the global rate limit of 1000 req/min if you spam this loop. Write a wrapper function that checks existence, creates if missing, and sleeps. This mirrors how Twilio Functions handle async DB writes, avoiding the race conditions you are seeing in Architect data actions.

How I usually solve this is by pre-filtering the csv with pandas. merge the csv against platformClient.user.searchUsers() results. keep only new emails. this avoids the 409 loop entirely. code: users_df = pd.read_csv(‘data.csv’); existing = pd.DataFrame(api.search()); new_users = users_df[~users_df.email.isin(existing.email)]