| name | zenstack-relation-naming-discovery |
| description | Discover actual ZenStack/Prisma relation field names when type errors occur.
Use when: (1) TypeScript errors like "Property 'verificationRecord' does not exist"
on model instances, (2) Runtime errors accessing relations, (3) Implementing new
features that query related data. Solves the problem of mismatched assumptions
about relation names vs actual schema-generated names.
|
| author | Claude Code |
| version | 1.0.0 |
| date | "2026-01-22T00:00:00.000Z" |
ZenStack Relation Naming Discovery
Problem
When working with ZenStack (enhanced Prisma), the actual relation field names on model
instances don't always match what you expect from reading the schema. This causes
TypeScript errors and runtime failures when accessing related data.
Common scenario: Schema defines verificationRecord VerificationRecord? but the
actual field name is verification, not verificationRecord.
Context / Trigger Conditions
Use this pattern when you encounter:
-
TypeScript errors like:
Property 'verificationRecord' does not exist on type 'User'
Property 'documentsOwned' does not exist on type 'User'
-
Runtime errors when accessing relations:
Cannot read property 'status' of undefined
-
Implementing new queries that need to include related data and you're unsure
of the exact field names
Solution
Step 1: Check the Schema Definition
Look at the schema in packages/database/zenstack/schema.zmodel (or .prisma file):
model User {
id String @id
verification VerificationRecord? // ← Note the field name here
documents Document[] // ← And here
}
model VerificationRecord {
id String @id
userId String @unique
user User @relation(fields: [userId], references: [id])
}
Key insight: The relation field name is determined by:
- Explicit name in schema:
verification VerificationRecord? → field name is verification
- Not the type name: The type
VerificationRecord doesn't determine the field name
Step 2: Verify with Generated Types
Check the generated TypeScript types in packages/database/zenstack/models.ts:
export type User = {
id: string;
verification?: VerificationRecord | null;
documents: Document[];
}
This shows the exact field names available on instances.
Step 3: Test with a Database Query (if still unsure)
Write a simple query to see what's actually available:
const user = await db.user.findUnique({
where: { id: 'some-id' },
include: {
verification: true,
documents: true
}
});
console.log(Object.keys(user));
Step 4: Update Your Code
Use the actual field names from the schema/types:
const status = instructor.verificationRecord?.status;
const docs = instructor.documentsOwned;
const status = instructor.verification?.status;
const docs = instructor.documents;
Verification
After using the correct field names:
- ✅ TypeScript errors disappear
- ✅ Queries execute without runtime errors
- ✅ Related data is properly accessed
Example
Scenario: Implementing admin verification UI, need to access instructor's verification
record and documents.
Initial attempt (based on assumptions):
const instructor = await baseDB.user.findUnique({
where: { id: instructorId },
include: {
verificationRecord: true,
documentsOwned: true,
},
});
After schema discovery:
const instructor = await baseDB.user.findUnique({
where: { id: instructorId },
include: {
verification: true,
documents: true,
},
});
Common Patterns
One-to-One Relations
model User {
profile Profile? // ← Field name: "profile"
}
// Access: user.profile (not user.userProfile)
One-to-Many Relations
model User {
vehicles Vehicle[] // ← Field name: "vehicles"
}
// Access: user.vehicles (not user.vehiclesOwned)
Many-to-Many Relations
model User {
languages UserLanguage[] // ← Field name: "languages"
}
// Access: user.languages (not user.userLanguages)
Relations with Type Tables
model Profile {
type ProfileType @relation(fields: [typeId], references: [id])
}
// Access: profile.type (not profile.profileType)
Notes
- Schema is source of truth: The field name in the schema definition is the actual
field name on instances
- Type name ≠ Field name:
verification VerificationRecord? creates a field called
verification, not verificationRecord
- Prisma conventions: Prisma (and ZenStack) follow these naming rules consistently
- Generated types are reliable: Always check
models.ts when in doubt
- Include syntax matches: The
include object uses the same field names as schema
References