Lỗi
Bạn đang chạy một macro Excel và hộp thoại bất ngờ xuất hiện:
Run-time error '1004':
Application-defined or object-defined error
Macro dừng hoàn toàn. Nhấn Debug và VBA tô vàng dòng lệnh gây lỗi — thường là những đoạn liên quan đến Range, Cells, ActiveSheet hoặc lệnh .Select.
Error 1004 là lỗi runtime tổng quát của Excel. Nó có thể mang hàng chục ý nghĩa khác nhau, đó là lý do tại sao nó rất khó chẩn đoán. Tuy nhiên, hầu hết các trường hợp đều rơi vào năm nhóm nguyên nhân. Nhận ra nhóm nào, áp dụng cách sửa tương ứng là xong.
Nguyên nhân
- Tham chiếu đến range trên sheet không phải sheet đang active khi dùng
.Selecthoặc.Activate - Gọi
.Selecttrên range thuộc workbook hoặc sheet khác với sheet đang active - Ghi vào sheet đang được bảo vệ
- Dùng địa chỉ range không hợp lệ — chuỗi rỗng, số hàng vượt quá 1.048.576 hoặc số cột vượt quá 16.384
- Truy cập named range không tồn tại trong workbook
- Dán vào vùng ô được merge khi kích thước dán không khớp
- Gọi
AutoFill,SorthoặcPasteSpecialtrên range rỗng hoặc không khớp
Cách sửa 1 — Ngừng dùng .Select và .Activate (Cách sửa phổ biến nhất)
Kết quả từ macro recorder là thủ phạm số 1. Khi bạn record một macro, Excel tạo ra code như thế này:
Sheets("Data").Select
Range("A1").Select
Selection.Value = "Hello"
Đoạn code này chỉ hoạt động nếu "Data" đang là sheet active lúc chạy. Ngay khi có thứ khác đang active — sheet khác, workbook khác — nó sẽ ném ra lỗi 1004. Hãy viết lại để tham chiếu trực tiếp đến sheet:
' TRƯỚC (dễ bị lỗi)
Sheets("Data").Select
Range("A1").Select
Selection.Value = "Hello"
' SAU (đáng tin cậy)
Sheets("Data").Range("A1").Value = "Hello"
Đây là mẫu đầy đủ để ghi vào sheet mà không cần active chúng:
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Data")
ws.Range("A1").Value = "Hello"
ws.Range("B2:B10").ClearContents
ws.Cells(3, 1).Value = 42
Cách sửa 2 — Kiểm tra bảo vệ sheet
Một sheet được bảo vệ sẽ ném ra Error 1004 ngay lập tức khi bạn cố ghi vào — không có ngoại lệ. Hãy bỏ bảo vệ trước khi ghi, rồi bảo vệ lại sau khi xong:
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Report")
' Bỏ bảo vệ trước khi ghi (dùng mật khẩu nếu có)
ws.Unprotect Password:="yourpassword"
ws.Range("C5").Value = "Updated"
' Bảo vệ lại sau khi xong
ws.Protect Password:="yourpassword"
Nếu bạn không biết mật khẩu và muốn bỏ qua thay vì gặp lỗi:
If Not ws.ProtectContents Then
ws.Range("C5").Value = "Updated"
Else
MsgBox "Sheet đang được bảo vệ. Không thể ghi."
End If
Cách sửa 3 — Kiểm tra tham chiếu range trước khi dùng
Một chuỗi rỗng hoặc số hàng ngoài phạm vi sẽ kích hoạt lỗi 1004 ngay lập tức. Giới hạn hàng tối đa của Excel là 1.048.576 — vượt quá con số này là crash. Hãy kiểm tra đầu vào trước:
' Sai: rowNum có thể là 0 hoặc âm
ws.Cells(rowNum, 1).Value = "data"
' Đúng: kiểm tra trước khi dùng
If rowNum >= 1 And rowNum <= ws.Rows.Count Then
ws.Cells(rowNum, 1).Value = "data"
Else
MsgBox "Số hàng ngoài phạm vi: " & rowNum
End If
Named range cũng cần xử lý tương tự. Đừng giả sử chúng tồn tại — hãy kiểm tra trước:
Function NamedRangeExists(wb As Workbook, nameStr As String) As Boolean
Dim nm As Name
On Error Resume Next
Set nm = wb.Names(nameStr)
NamedRangeExists = (Not nm Is Nothing)
On Error GoTo 0
End Function
' Cách dùng
If NamedRangeExists(ThisWorkbook, "SalesData") Then
ThisWorkbook.Names("SalesData").RefersToRange.Value = 0
End If
Cách sửa 4 — Sửa lỗi PasteSpecial và AutoFill
PasteSpecial thất bại khi clipboard trống hoặc bạn đang dán vào vùng không tương thích — ô merge là bẫy phổ biến. Luôn copy trước, sau đó chỉ dán giá trị để tránh xung đột định dạng:
' Sao chép nguồn
wsSource.Range("A1:A10").Copy
' Chỉ dán giá trị vào đích (tránh xung đột định dạng)
wsDest.Range("B1").PasteSpecial Paste:=xlPasteValues
' Xóa clipboard sau khi dán
Application.CutCopyMode = False
AutoFill có yêu cầu nghiêm ngặt hơn: range đích phải bắt đầu từ cùng ô với range nguồn. Lệch dù chỉ một chút là bạn sẽ gặp lỗi 1004:
Dim srcRange As Range
Dim fillRange As Range
Set srcRange = ws.Range("A1:A2")
' Range đích phải BẮT ĐẦU từ cùng ô với nguồn
Set fillRange = ws.Range("A1:A10")
srcRange.AutoFill Destination:=fillRange, Type:=xlFillDefault
Cách sửa 5 — Workbook chưa mở hoặc tham chiếu workbook sai
Tham chiếu đến workbook theo tên khi nó chưa mở sẽ khiến Excel ném ra lỗi 1004. Dùng ThisWorkbook khi bạn muốn tham chiếu đến file chứa macro — nó luôn sẵn sàng bất kể những gì khác đang mở:
' Rủi ro: giả sử workbook đã mở và tên chính xác
Workbooks("Report_2024.xlsx").Sheets("Data").Range("A1").Value = 1
' An toàn: tham chiếu workbook chứa macro này
ThisWorkbook.Sheets("Data").Range("A1").Value = 1
' Hoặc dùng vòng lặp để tìm workbook đang mở cụ thể
Dim wb As Workbook
For Each wb In Application.Workbooks
If wb.Name = "Report_2024.xlsx" Then
wb.Sheets("Data").Range("A1").Value = 1
Exit For
End If
Next wb
Debug: Tìm dòng lỗi chính xác
Khi hộp thoại lỗi xuất hiện, nhấn Debug. VBA sẽ tô vàng dòng gây lỗi. Từ đó:
- Di chuột qua các biến để xem giá trị hiện tại trong tooltip
- Mở Immediate Window (
Ctrl+G) và gõ? variableNameđể kiểm tra giá trị - Thêm lệnh
Stopngay trước dòng lỗi để tạm dừng thực thi và kiểm tra trạng thái
' Debug tạm thời — xóa trước khi triển khai
Stop ' Thực thi dừng lại tại đây
ws.Range(rangeAddress).Value = newValue
Phòng ngừa
- Tái cấu trúc toàn bộ code macro được record — loại bỏ mọi
.Selectvà.Activatetrước khi triển khai - Luôn khai báo đầy đủ tham chiếu range với biến sheet:
ws.Range(...)thay vì chỉRange(...) - Thêm xử lý
On Error GoTotrong macro sản xuất để hiển thị thông báo lỗi có nghĩa - Bỏ bảo vệ sheet ở đầu mọi macro ghi dữ liệu, bảo vệ lại ở cuối
- Kiểm tra các giá trị động (số hàng, chuỗi range) trước khi truyền vào lệnh range
Kiểm tra kết quả
Nhấn F5 trong VBA editor để chạy từ đầu. Không có hộp thoại lỗi nghĩa là đã thành công. Sau đó kiểm tra các trường hợp biên:
- Chạy trên sheet trống
- Chạy khi sheet được bảo vệ đang active
- Truyền đầu vào không hợp lệ — số hàng bằng 0, chuỗi range rỗng
- Xóa mọi lệnh
Stophoặc debug trước khi phát hành phiên bản cuối

