Prisma "Ambiguous relation detected": name both relations
Turn a P1012 "Ambiguous relation detected" into a valid referral schema: what the validator compares, the second error naming uncovers, and three tested models.
TL;DR#
Error validating model "User": Ambiguous relation detected means one model has two relation fields that point to the same model, and neither relation has a name. Prisma pairs the two ends of a relation by name; without one, both pairs get the same generated name and the validator cannot tell which Referral field belongs to which User field. The fix is to name each relation with @relation("Name") and to use the same name on both sides of each pair, a different name per pair. Then run npx prisma validate again: on the schema from the original question, naming the relations immediately exposes a second error, because a User[] list with fields over an Int[] column is not a PostgreSQL relation. The models below were all checked with prisma validate on Prisma 7.10.1.
The error#
The Stack Overflow question models a referral table for PostgreSQL: each user has one referral record, and the record lists the users it brought in. The User model gets two back-relation fields, Referral and UsersReferred, and validation stops. Reproduced with the question's schema (s1/schema.prisma) in a node:22-alpine container, Prisma CLI 7.10.1, on 20 October 2026:
Error: Prisma schema validation - (validate wasm)
Error code: P1012
error: Error validating model "User": Ambiguous relation detected. The fields `Referral` and `UsersReferred` in model `User` both refer to `Referral`. Please provide different relation names for them by adding `@relation(<name>).The schema that produced it, with a minimal User model added so the file can be validated on its own:
datasource db {
provider = "postgresql"
}
model User {
id Int @id @default(autoincrement())
Referral Referral?
UsersReferred Referral[]
}
model Referral {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @default(now())
referId String
userId Int @unique
user User @relation(fields: [userId], references: [id])
referredUsersId Int[]
referredUsers User[] @relation(fields: [referredUsersId], references: [id])
}Every other schema error in this article also came back under P1012, so the message text, not the code, tells you which rule broke.
Why Prisma cannot pair the fields#
A relation in Prisma has two ends, one on each model. When there is only one relation between User and Referral, Prisma matches the ends without help. When there are two, it needs a name to know that Referral.user goes with User.Referral and Referral.referredUsers goes with User.UsersReferred.
The check lives in the schema validator of prisma-engines. It groups relation fields by three things: the model they are in, the model they point to, and the relation name. An unnamed relation gets a generated name, and two unnamed relations between the same pair of models get the same generated name. So Referral and UsersReferred in User fall into one group of two, and the validator emits the message above. Field names play no part, because the group key does not include them: renaming UsersReferred to referredList (s13/schema.prisma) gives the same error with the new field name in it.
The Prisma ORM 7 relations documentation lists disambiguation as one of the cases where @relation is required, and states the rule that matters for the fix:
The
namemust be the same on both sides of the relation.
The same file decides three neighbouring messages, which is useful when the text you see is slightly different:
| Message | What the validator found |
|---|---|
Ambiguous relation detected | two unnamed relations between the same two models |
Ambiguous self relation detected | a model with one unnamed relation to itself (two fields) |
Wrongly named relation detected | two relations between the same models with the same explicit name |
Fix: give each relation its own name#
- Pick one name per relation and write it on both ends. Here
UserReferralis the owner of a referral record andReferredUsersis the people it brought in:
model User {
id Int @id @default(autoincrement())
Referral Referral? @relation("UserReferral")
UsersReferred Referral[] @relation("ReferredUsers")
}- Put the matching name in front of
fieldson theReferralside:
model Referral {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @default(now())
referId String
userId Int @unique
user User @relation("UserReferral", fields: [userId], references: [id])
referredUsersId Int[]
referredUsers User[] @relation("ReferredUsers", fields: [referredUsersId], references: [id])
}- Validate the schema without touching a database:
npx prisma validate --schema prisma/schema.prismaThe name: argument form used in the accepted answer, @relation(fields: [userId], references: [id], name: "UserReferral"), is equivalent to the positional form above.
Naming the relations reveals a second error#
On the question's schema, step 3 does not print "valid". The unnamed schema reported only the ambiguity error; with the names in place (s2/schema.prisma), the validator reports the Int[] list instead:
error: Error validating: Embedded many-to-many relations are not supported on Postgres. Please use the syntax defined in https://pris.ly/d/relational-database-many-to-many
--> s2/schema.prisma:22A User[] field that carries fields and references over an Int[] column stores the foreign keys inside the row, which the message calls an embedded many-to-many relation, and Prisma rejects it on PostgreSQL. The many-to-many relations page is where the pris.ly link in the message points. For a referral system you do not need a many-to-many at all: one user brings in many users, and each user is brought in by at most one referrer. That is a one-to-many, and the foreign key goes on the "many" side.
Three referral models that validate#
All three were checked with npx prisma validate on Prisma 7.10.1 and print The schema at … is valid.
Keep the referral record, move the foreign key to User (s11/schema.prisma). This is the closest to what the question describes: one Referral row per owner, and each referred user points at the referral that brought them in.
model User {
id Int @id @default(autoincrement())
referral Referral? @relation("ReferralOwner")
referredById Int?
referredBy Referral? @relation("ReferredUsers", fields: [referredById], references: [id])
}
model Referral {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
referId String @unique
userId Int @unique
user User @relation("ReferralOwner", fields: [userId], references: [id])
referredUsers User[] @relation("ReferredUsers")
}One row per referral event (s4/schema.prisma). Use this when each referral needs its own data, such as when it happened or whether a reward was paid. The @unique on referredId stops a user from being referred twice.
model User {
id Int @id @default(autoincrement())
referralCode String @unique
referralsMade Referral[] @relation("ReferralsMade")
referredBy Referral? @relation("ReferredBy")
}
model Referral {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
referrerId Int
referrer User @relation("ReferralsMade", fields: [referrerId], references: [id])
referredId Int @unique
referred User @relation("ReferredBy", fields: [referredId], references: [id])
@@index([referrerId])
}No referral table, a self-relation on User (s8/schema.prisma). The smallest model, when the code can live on User and nothing else is stored per referral:
model User {
id Int @id @default(autoincrement())
referredById Int?
referredBy User? @relation("Referrals", fields: [referredById], references: [id])
referrals User[] @relation("Referrals")
}What the accepted answer changes besides the names#
The accepted answer on Stack Overflow does name the relations, and its schema validates (reproduced as s5/schema.prisma). To get there it also changes referredUsersId Int[] with User[] into a single referredUsersId String with User. Read against the schema, that inverts the cardinality the question asked for: userId is @unique, so each user owns at most one Referral row, and each row holds exactly one referredUsersId. A referrer can then refer one user, while UsersReferred lists every row in which a user was the one referred. If a referrer should bring in many users, use one of the three models above.
The answer also switches the ids from Int to String. That is not part of the fix: the same named schema with Int ids (s3/schema.prisma) validates as well.
Verify the fix#
Run the validator; it reads only the schema file:
npx prisma validate --schema prisma/schema.prismaA fixed schema prints:
The schema at s11/schema.prisma is valid 🚀Inside a project with Prisma ORM 7 installed, npx prisma runs that version. Outside a project, npx prisma downloads the latest npm tag, which on 20 October 2026 was the Prisma 8 release candidate 8.0.0-rc.23; these schemas were not tested on it, so pin npx prisma@7 if you validate a file on its own. After validation passes, npx prisma migrate dev creates the foreign keys. If the migration then fails with FATAL: bouncer config error or hangs against Supabase, the cause is the connection URL, not the schema: Prisma migrations with Supabase covers the pooled-port case and where the URL goes in prisma.config.ts on Prisma 7. And if prisma and @prisma/client were upgraded separately along the way, the Prisma v7 version mismatch fix applies.
One email a month — the latest explained errors
What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.
When the two relations point at the same model#
If the referral link lives on User itself and neither end is named, the message changes to the self-relation variant. With only referredBy and referrals (s9/schema.prisma):
error: Error validating model "User": Ambiguous self relation detected. The fields `referredBy` and `referrals` in model `User` both refer to `User`. If they are part of the same relation add the same relation name for them with `@relation(<name>)`.Here the advice is the opposite of the two-model case: both fields belong to one relation, so they take the same name, as in the self-relation model above. With a second self-relation in the same model, for example mentor and mentees next to the referral pair (s7/schema.prisma), Prisma reports Unnamed self relation detected; naming the pairs "Referrals" and "Mentoring", each name on both fields of its pair (s12/schema.prisma), validates. The self-relations page has the pattern for one-to-one, one-to-many and many-to-many.
Two mistakes are common while adding names. Giving both two-model relations the same name (s10/schema.prisma) gives:
error: Error validating model "User": Wrongly named relation detected. The fields `Referral` and `UsersReferred` in model `User` both use the same relation name. Please provide different relation names for them through `@relation(<name>).And a typo on one side, "ReferredUser" against "ReferredUsers" (s6/schema.prisma), leaves each end without a partner:
error: Error validating field `UsersReferred` in model `User`: The relation field `UsersReferred` on model `User` is missing an opposite relation field on the model `Referral`. Either run `prisma format` or add it manually.After the schema validates: deleting a referrer#
Where fields and references sit decides who owns the foreign key, and that decides what a delete does later. The referential actions page gives the defaults when onDelete is not set: SetNull for optional relations and Restrict for mandatory ones. In the first model above, Referral.user is mandatory, so deleting a user who still owns a referral record is refused by the foreign key, while deleting a Referral clears referredById on the users it brought in. If that delete fails with P2003, Prisma deleteMany: Foreign key constraint failed walks through ordering the deletes or setting onDelete: Cascade with a migration.
The error looks like a naming nit, but it is Prisma asking which end of which relation you meant. Answer it with one name per relation, read the next validator message rather than assuming the schema is done, and check that the cardinality the schema now encodes is the one your referral rules need.
Frequently Asked Questions
Still stuck? Paste your error.
Paste the error message or stack trace — we check it against every fix and tool on the site.
Continue Reading
Prisma: Can't reach database server at database:5432 on M1
Check the address seen by the app container, preserve the PostgreSQL volume and distinguish a reachable database from a healthy container.
Fix Prisma 'Unique constraint failed on the fields: (id)'
Prove in two queries that the id sequence is stuck behind your imported rows, reset it safely even on an empty table, and see why retrying seems to fix it.
Prisma Migrate P3014: permission denied to create database
Hit `P3014: permission denied to create database` when running Prisma Migrate on Heroku Postgres? Use prisma db push, a separate shadow database, or grant CREATEDB — and fix hangs with Supabase pooled connections.


