As far as the application code goes, but most systems have databases which opens you up to all kinds of race conditions. Does Elixir help in that case?
My experience with databases in Erlang was using the pattern where one process recieves a high level message and does the database work was best. If you can split the queue in a sensible way, that gives you concurrency; for example if all the requests address a single user, you can hash users into as many buckets as you need for concurrency; if the individual requests take a long time, it might make more sense to keep a scoreboard of if a user has a process working for it, and send further requests there, otherwise to an idle process (or spawn).
You do need to manage this somehow, but the building blocks are there. Of course, the building blocks for transactionless database access are there too.
Modern relation databases are not a concern at all. You get race conditions if the developer has only a passing knowledge of SQL, because otherwise that's a basically solved problem, with the existence of transactions, isolation modes, etc. If all else fails, your query throws an error, but it does not corrupt your database.
Much more common instead are race conditions on local storage, external APIs and traditional memory races when using unsophisticated languages.
Races and deadlocks are certainly possible in pure Erlang/Elixir - no databases or global state required. There is no magic bullet.
For example, if you use blocking RPCs between two processes, they can deadlock waiting for each other's responses. Try implementing Dining Philosophers, you will learn a lot.
The answer is not to use blocking RPC, but that will challenge your brain topology. It takes some time to be able to lower yourself into the hot bath of full asynchrony, but when you do, it feels very very good.
I characterize it as the co-problem (in the sense of the dual of a problem). Distributing a problem, starting processes and pushing messages is easy. But it may be hard to know when you're finished. Everything is easy, but termination is difficult. It's the Erlang/Elixir Halting Problem.
It is not often mentioned as a strong feature for concurrent programming, but Erlang/Elixir have timeouts built into the language. And when you add OTP supervisor restarts, you can avoid some common programming mistakes through random evasion - don't do this by design, but it does help resilience.
Races within an elixir application are still possible it is just data races that are prevented. For example if you have a bank account in an elixir process nothing will stop you from implementing a withdrawal as 2 external operations: read balance, write balance which is inherently racy but not a data race.
You do need to manage this somehow, but the building blocks are there. Of course, the building blocks for transactionless database access are there too.