Fix: TypeORM QueryFailedError and Entity Not Found
Quick Answer
How to fix TypeORM QueryFailedError, entity not found errors, relation issues, missing migrations, and connection configuration problems in Node.js and NestJS applications.
The Error
TypeORM throws a QueryFailedError or entity-related error:
QueryFailedError: relation "user" does not exist
at PostgresQueryRunner.query (/app/node_modules/typeorm/driver/postgres/PostgresQueryRunner.js:...)
Error: Entity metadata for User#posts was not found.
Check if you specified a correct entity object and if it's registered in your current "default" connection.Or a relation error:
EntityNotFoundError: Could not find any entity of type "User" matching: { "id": 42 }Or a migration issue:
QueryFailedError: column "created_at" of relation "user" does not existOr connection fails with:
Error: connect ECONNREFUSED 127.0.0.1:5432
Cannot connect to the database. Connection refused.Why This Happens
TypeORM maps TypeScript classes to database tables with a complex layer of metadata, migrations, and connection configuration:
- Entity not registered — the entity class is defined but not included in the
entitiesarray in the DataSource configuration. TypeORM can’t find metadata for unregistered entities. - Table doesn’t exist — migrations haven’t been run, or
synchronize: trueis off. The TypeScript entity exists but no corresponding database table was created. - Column added to entity but migration not generated — you added a field to an entity class, but the database column doesn’t exist yet.
- Relation metadata missing — a
@ManyToOne,@OneToMany, or@ManyToManyrelation references an entity that isn’t registered in the same DataSource. - Wrong connection name — using multiple DataSources and referencing the wrong connection name in a repository or
getConnection(). synchronize: truein production —synchronize: trueauto-applies schema changes on startup, which can drop columns and data unexpectedly.
Fix 1: Register All Entities in DataSource
Every entity class must be listed in the entities array (or matched by a glob pattern):
// data-source.ts
import { DataSource } from 'typeorm';
import { User } from './entities/User';
import { Post } from './entities/Post';
import { Comment } from './entities/Comment';
export const AppDataSource = new DataSource({
type: 'postgres',
host: process.env.DB_HOST ?? 'localhost',
port: parseInt(process.env.DB_PORT ?? '5432'),
username: process.env.DB_USER,
password: process.env.DB_PASS,
database: process.env.DB_NAME,
// Option 1: List entities explicitly
entities: [User, Post, Comment],
// Option 2: Glob pattern (picks up all entity files automatically)
// entities: [__dirname + '/entities/**/*.entity{.ts,.js}'],
migrations: [__dirname + '/migrations/**/*{.ts,.js}'],
synchronize: false, // Never true in production
});Common mistake — using a glob pattern but the compiled JS files are in a different directory than the TS source:
// Development (ts-node): __dirname = src/
entities: [__dirname + '/entities/**/*.entity.ts'],
// Production (compiled): __dirname = dist/
// This still looks for .ts files which don't exist in dist/
// Fix — use {.ts,.js} to match both
entities: [__dirname + '/entities/**/*.entity{.ts,.js}'],Fix 2: Run Pending Migrations
If the table or column doesn’t exist, generate and run migrations:
# Generate a migration from entity changes
npx typeorm migration:generate -d src/data-source.ts src/migrations/AddCreatedAt
# Run pending migrations
npx typeorm migration:run -d src/data-source.ts
# Check migration status
npx typeorm migration:show -d src/data-source.tsIn code — run migrations on app startup:
// main.ts
import { AppDataSource } from './data-source';
async function main() {
await AppDataSource.initialize();
// Run pending migrations before starting the server
const pendingMigrations = await AppDataSource.showMigrations();
if (pendingMigrations) {
console.log('Running pending migrations...');
await AppDataSource.runMigrations();
console.log('Migrations complete');
}
// Start the server
app.listen(3000);
}Warning: Never use
synchronize: truein production. It compares entity definitions to the database schema and automatically drops/creates tables and columns — including dropping columns that contain data. Use migrations instead.
Fix 3: Fix Entity Relation Errors
When a relation references an entity that isn’t in the same DataSource or has a circular dependency:
// User.entity.ts
import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm';
import { Post } from './Post.entity';
@Entity('users')
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@OneToMany(() => Post, (post) => post.author)
posts: Post[];
}// Post.entity.ts
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';
import { User } from './User.entity';
@Entity('posts')
export class Post {
@PrimaryGeneratedColumn()
id: number;
@Column()
title: string;
@ManyToOne(() => User, (user) => user.posts)
@JoinColumn({ name: 'author_id' })
author: User;
}Both User and Post must be registered in the same DataSource. If only User is registered, loading user.posts will throw “Entity metadata for Post not found.”
Load relations explicitly when querying:
// Relations are NOT loaded by default
const user = await userRepo.findOne({ where: { id: 1 } });
console.log(user.posts); // undefined — not loaded
// Load with relations
const user = await userRepo.findOne({
where: { id: 1 },
relations: { posts: true }, // Explicitly load posts
});
console.log(user.posts); // Post[] ✓
// Or use QueryBuilder for complex loading
const user = await userRepo
.createQueryBuilder('user')
.leftJoinAndSelect('user.posts', 'post')
.where('user.id = :id', { id: 1 })
.getOne();Fix 4: Fix findOne and EntityNotFoundError
TypeORM’s findOne() returns null (not throws) when no record is found. findOneOrFail() throws EntityNotFoundError:
// findOne returns null — no exception
const user = await userRepo.findOne({ where: { id: 999 } });
if (!user) {
throw new NotFoundException('User not found');
}
// findOneOrFail throws EntityNotFoundError
try {
const user = await userRepo.findOneOrFail({ where: { id: 999 } });
} catch (e) {
if (e instanceof EntityNotFoundError) {
throw new NotFoundException('User not found');
}
throw e;
}In NestJS, handle TypeORM exceptions in a filter:
// typeorm-exception.filter.ts
import { Catch, ExceptionFilter, ArgumentsHost, HttpStatus } from '@nestjs/common';
import { EntityNotFoundError, QueryFailedError } from 'typeorm';
import { Response } from 'express';
@Catch(EntityNotFoundError, QueryFailedError)
export class TypeOrmExceptionFilter implements ExceptionFilter {
catch(exception: EntityNotFoundError | QueryFailedError, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
if (exception instanceof EntityNotFoundError) {
return response.status(HttpStatus.NOT_FOUND).json({ error: 'Not found' });
}
// QueryFailedError — check for unique constraint violation
if (exception instanceof QueryFailedError) {
const detail = (exception as any).detail ?? '';
if (detail.includes('already exists')) {
return response.status(HttpStatus.CONFLICT).json({ error: 'Already exists' });
}
}
return response.status(HttpStatus.INTERNAL_SERVER_ERROR).json({ error: 'Database error' });
}
}Fix 5: Fix NestJS TypeORM Module Configuration
In NestJS, entities must be registered in TypeOrmModule.forFeature() in the module that uses them:
// app.module.ts — global DataSource configuration
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'postgres',
host: process.env.DB_HOST,
port: +process.env.DB_PORT,
username: process.env.DB_USER,
password: process.env.DB_PASS,
database: process.env.DB_NAME,
entities: [__dirname + '/**/*.entity{.ts,.js}'],
synchronize: false,
}),
UsersModule,
PostsModule,
],
})
export class AppModule {}// users.module.ts — register entities for this module
@Module({
imports: [
TypeOrmModule.forFeature([User, Post]), // Makes UserRepository and PostRepository injectable
],
providers: [UsersService],
controllers: [UsersController],
})
export class UsersModule {}// users.service.ts — inject repositories
@Injectable()
export class UsersService {
constructor(
@InjectRepository(User)
private userRepo: Repository<User>,
@InjectRepository(Post)
private postRepo: Repository<Post>,
) {}
async findAll(): Promise<User[]> {
return this.userRepo.find({ relations: { posts: true } });
}
}Fix 6: Fix Migration Drift
When the database schema drifts from entity definitions (tables added manually, old migrations not applied), TypeORM’s migration generation can produce incorrect migrations:
# Check what TypeORM thinks the current schema is
npx typeorm schema:log -d src/data-source.ts
# Generate a migration to reconcile the current state
npx typeorm migration:generate -d src/data-source.ts src/migrations/SyncSchema
# Review the generated migration CAREFULLY before running
# Auto-generated migrations can drop columns you want to keep
cat src/migrations/$(ls src/migrations/ | tail -1)Run migrations in a transaction — if any migration step fails, the whole migration rolls back:
// In your migration class
import { MigrationInterface, QueryRunner } from 'typeorm';
export class AddUserTable1234567890 implements MigrationInterface {
async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.startTransaction();
try {
await queryRunner.query(`CREATE TABLE "user" (...)`);
await queryRunner.query(`CREATE INDEX "IDX_user_email" ON "user" ("email")`);
await queryRunner.commitTransaction();
} catch (err) {
await queryRunner.rollbackTransaction();
throw err;
}
}
async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP TABLE "user"`);
}
}Still Not Working?
Enable TypeORM query logging to see the exact SQL being executed:
const AppDataSource = new DataSource({
// ...
logging: true, // Log all queries
// logging: ['query', 'error'], // Only queries and errors
logger: 'advanced-console',
});Check the compiled output. If using ts-node in development and node dist/ in production, the entity paths must work for both. Glob patterns with {.ts,.js} handle this:
entities: [path.join(__dirname, '**', '*.entity.{ts,js}')],Verify the database exists before running migrations. TypeORM doesn’t create the database itself — only tables:
psql -U postgres -c "CREATE DATABASE myapp;"
# Then run migrations
npx typeorm migration:run -d src/data-source.tsFor related database issues, see Fix: Prisma Migration Failed and Fix: Postgres Relation Does Not Exist.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: Drizzle ORM Not Working — Schema Out of Sync, Relation Query Fails, or Migration Error
How to fix Drizzle ORM issues — schema definition, drizzle-kit push vs migrate, relation queries with, transactions, type inference, and common PostgreSQL/MySQL configuration problems.
Fix: Prisma Transaction Error — Transaction Already Closed or Rolled Back
How to fix Prisma transaction errors — interactive transactions vs $transaction array, error handling and rollback, nested transactions, timeout issues, and isolation levels.
Fix: Fastify Not Working — 404, Plugin Encapsulation, and Schema Validation Errors
How to fix Fastify issues — route 404 from plugin encapsulation, reply already sent, FST_ERR_VALIDATION, request.body undefined, @fastify/cors, hooks not running, and TypeScript type inference.
Fix: Neon Database Not Working — Connection Timeout, Branching Errors, or Serverless Driver Issues
How to fix Neon Postgres issues — connection string setup, serverless HTTP driver vs TCP, database branching, connection pooling, Drizzle and Prisma integration, and cold start optimization.