Skip to content

Fix: TypeORM QueryFailedError and Entity Not Found

FixDevs ·

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 exist

Or 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 entities array in the DataSource configuration. TypeORM can’t find metadata for unregistered entities.
  • Table doesn’t exist — migrations haven’t been run, or synchronize: true is 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 @ManyToMany relation 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: true in productionsynchronize: true auto-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.ts

In 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: true in 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.ts

For related database issues, see Fix: Prisma Migration Failed and Fix: Postgres Relation Does Not Exist.

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles