Sửa lỗi Mongoose 'OverwriteModelError: Cannot overwrite model once compiled'

beginner🍃 MongoDB2026-06-13| Node.js (tất cả phiên bản), Mongoose (v5, v6, v7, v8), Next.js, và các môi trường Serverless như AWS Lambda hoặc Vercel Functions.

Error Message

OverwriteModelError: Cannot overwrite model once compiled.
#mongoose#nodejs#mongodb#nextjs#serverless

Tình huống lỗiHãy tưởng tượng: bạn đang trong giai đoạn nước rút xây dựng một API Node.js. Mọi thứ diễn ra suôn sẻ cho đến khi bạn chỉnh sửa một schema và nhấn lưu. Server phát triển của bạn—cho dù là Nodemon hay Next.js dev server—khởi động lại trong chưa đầy 200ms. Đột nhiên, terminal của bạn tràn ngập các dòng stack trace màu đỏ:

OverwriteModelError: Cannot overwrite model once compiled.

Đây không phải là lỗi logic của bạn. Đó là sự xung đột giữa cách Mongoose xử lý việc đăng ký model và cách các công cụ hiện đại sử dụng Hot Module Replacement (HMR). Khi môi trường của bạn tải lại một file mà không tắt hoàn toàn process, Mongoose nghĩ rằng bạn đang cố gắng định nghĩa lại một model đã tồn tại.

Phân tích: Tại sao Mongoose lại báo lỗiMongoose duy trì một registry trung tâm cho mọi model bạn tạo. Khi bạn gọi mongoose.model('User', UserSchema), Mongoose sẽ biên dịch schema đó và lưu trữ trong bộ nhớ cache nội bộ. Nếu luồng thực thi của bạn chạy qua dòng đó lần thứ hai, Mongoose giả định rằng bạn đang cố ghi đè model 'User' bằng một schema mới.

Theo mặc định, Mongoose chặn việc này để ngăn chặn tình trạng hỏng dữ liệu ngoài ý muốn hoặc các hành vi không mong muốn. Trong môi trường production tiêu chuẩn, đây là một tính năng an toàn. Tuy nhiên, trong các serverless function hoặc môi trường phát triển local, ngữ cảnh thực thi (execution context) thường xuyên được tái sử dụng, khiến việc kiểm tra an toàn này trở thành một rào cản lớn.

Giải pháp nhanh: Conditional ExportThay vì định nghĩa model một cách mù quáng, bạn nên kiểm tra xem nó đã tồn tại trong đối tượng mongoose.models hay chưa. Pattern này đảm bảo bạn sẽ tái sử dụng phiên bản đã có trong cache hoặc chỉ tạo mới khi thực sự cần thiết.

Cập nhật file model của bạn (ví dụ: models/User.js) với logic sau:

const mongoose = require('mongoose');

const UserSchema = new mongoose.Schema({
  name: String,
  email: { type: String, unique: true },
});

// Giải pháp: Kiểm tra registry trước khi biên dịch
const User = mongoose.models.User || mongoose.model('User', UserSchema);

module.exports = User;

Dòng mã này báo cho engine biết: "Nếu model User đã có trong cache, hãy sử dụng nó. Nếu chưa, hãy biên dịch ngay bây giờ." Đây là cách hiệu quả nhất để giữ cho dev server của bạn luôn ổn định.

Xử lý trong môi trường Next.js và ServerlessNext.js tải lại các API route liên tục trong quá trình phát triển. Điều này khiến lỗi OverwriteModelError gần như không thể tránh khỏi trừ khi bạn sử dụng singleton pattern. Ngoài việc sửa lỗi model, bạn cũng nên ngăn ứng dụng tạo kết nối database mới sau mỗi lần reload, điều này có thể nhanh chóng làm cạn kiệt giới hạn 100 kết nối trên các database miễn phí như MongoDB Atlas.

Sử dụng một tiện ích kết nối tập trung để quản lý việc này:

// lib/db.js
import mongoose from 'mongoose';

const MONGODB_URI = process.env.MONGODB_URI;

if (!MONGODB_URI) {
  throw new Error('Vui lòng định nghĩa biến môi trường MONGODB_URI');
}

let cached = global.mongoose;

if (!cached) {
  cached = global.mongoose = { conn: null, promise: null };
}

async function dbConnect() {
  if (cached.conn) return cached.conn;

  if (!cached.promise) {
    cached.promise = mongoose.connect(MONGODB_URI).then((m) => m);
  }
  cached.conn = await cached.promise;
  return cached.conn;
}

export default dbConnect;

Kết hợp tiện ích kết nối này với việc export model có điều kiện sẽ tạo ra một lớp dữ liệu bền bỉ. Nó vừa ngăn chặn rò rỉ kết nối (connection leak), vừa xử lý triệt để lỗi biên dịch.

Khi bạn thực sự cần ghi đèCó một số trường hợp hiếm hoi bạn thực sự muốn ghi đè một model, chẳng hạn như trong một REPL tùy chỉnh hoặc bộ test động. Nếu bạn rơi vào tình huống process vẫn chạy nhưng schema đã thay đổi, bạn có thể xóa cache một cách thủ công:

if (mongoose.models.User) {
  delete mongoose.models.User;
}
const User = mongoose.model('User', UserSchema);

Hãy thận trọng khi sử dụng cách này. Việc xóa khỏi mongoose.models trong môi trường production có thể dẫn đến rò rỉ bộ nhớ hoặc sai lệch schema nếu các phần khác của ứng dụng vẫn đang sử dụng instance cũ.

Xác minh kết quảĐể xác nhận lỗi đã được khắc phục, hãy thực hiện ba bước sau:

  • Kích hoạt Reload: Lưu file model của bạn. Server sẽ khởi động lại một cách êm thấm mà không có bất kỳ dòng chữ đỏ nào trong terminal.- Kiểm tra Registry: Thêm console.log(Object.keys(mongoose.models)) vào API route của bạn. Bạn sẽ thấy tên các model được liệt kê rõ ràng.- Thực hiện truy vấn: Chạy một lệnh User.findOne() cơ bản. Nếu nó trả về dữ liệu mà không phàn nàn về schema, model trong cache của bạn đang hoạt động hoàn hảo.Khi stack trace màu đỏ biến mất, môi trường của bạn đã được cấu hình đúng cho các quy trình phát triển hiện đại.

Related Error Notes