Vấn đề
Bạn đang chạy Google Apps Script, mọi thứ dường như đều ổn, và rồi—bùm. Một thông báo lỗi màu đỏ khiến bạn phải dừng lại:
Exception: The coordinates or dimensions of the range are invalid.
Lỗi này là cách Google thông báo: "Tôi không thể tìm thấy ô bạn đang tìm kiếm." Nói một cách dễ hiểu, bạn đã yêu cầu dịch vụ SpreadsheetApp xem xét một ô hoặc vùng (range) không tồn tại trên lưới bảng tính. Khác với các mảng JavaScript tiêu chuẩn khi một chỉ số ngoài phạm vi sẽ âm thầm trả về undefined, Apps Script sẽ ném ra một ngoại lệ nghiêm trọng (hard exception) làm dừng kịch bản của bạn ngay lập tức.
Tóm tắt: Cách khắc phục nhanh
Hãy kiểm tra các con số bên trong lệnh gọi getRange() của bạn. Nhiều khả năng, một trong hai điều sau đã xảy ra lỗi:
- Bạn đã sử dụng số 0 hoặc số âm. Google Sheets bắt đầu chỉ số từ 1 (1-indexed). Ô đầu tiên luôn là (1, 1), không phải (0, 0).
- Bạn đã yêu cầu vượt quá phạm vi. Bạn đang cố gắng truy cập hàng 1.001 trên một trang tính chỉ có tổng cộng 1.000 hàng.
Tại sao điều này lại xảy ra?
1. Bẫy "Chỉ số 0" (Zero Index)
Là lập trình viên, chúng ta thường có thói quen bắt đầu đếm từ 0. Các mảng JavaScript bắt đầu tại data[0], nhưng Google Sheets bắt đầu từ 1. Nếu bạn sử dụng chỉ số vòng lặp i trực tiếp trong lệnh gọi getRange, kịch bản của bạn sẽ bị lỗi ngay khi thực hiện lần lặp đầu tiên.
// ❌ LỖI: Vòng lặp bắt đầu từ 0, nhưng Sheets bắt đầu từ 1
for (var i = 0; i < data.length; i++) {
sheet.getRange(i, 1).setValue(data[i]);
}
Cách khắc phục: Luôn sử dụng i + 1 khi chuyển đổi một chỉ số mảng sang tọa độ trang tính.
2. "Bóng ma" dữ liệu trống
Nếu bạn đang ghi dữ liệu một cách linh hoạt, bạn có thể sử dụng data.length để xác định số lượng hàng cần điền. Nếu nguồn dữ liệu của bạn trả về một mảng trống, getRange(1, 1, 0, 1) sẽ thất bại vì một vùng không thể có chiều cao bằng 0. Ngay cả khi bạn có tọa độ bắt đầu chính xác, một kích thước có độ dài bằng không là không hợp lệ.
var values = getExternalData(); // Giả sử hàm này trả về []
// ❌ LỖI: values.length bằng 0
sheet.getRange(1, 1, values.length, 1).setValues(values);
3. Nhầm lẫn với getLastRow()
Sử dụng getLastRow() + 1 là cách tiêu chuẩn để tìm hàng trống tiếp theo. Tuy nhiên, nếu một trang tính mới hoàn toàn và trống rỗng, getLastRow() trả về 0. Mặc dù getRange(0 + 1, 1) vẫn hoạt động, các logic phức tạp hơn—như tính toán các khoảng cách (offsets)—thường dẫn đến việc số 0 được truyền vào tham số cột hoặc kích thước, gây ra lỗi.
4. Chạm đến giới hạn của bảng tính
Nếu bạn cố gắng truy cập getRange(1, 1, 1, 30) trên một trang tính chỉ kéo dài từ Cột A đến Z (26 cột), kịch bản sẽ thất bại. Apps Script không tự động "co giãn" theo mặc định; nó sẽ không tự động tạo Cột AC chỉ vì bạn yêu cầu. Bạn phải tạo không gian đó trước.
Các cách khắc phục đã được kiểm chứng
Cách 1: Kiểm soát dữ liệu với Math.max()
Đừng tin tưởng mù quáng vào các tính toán của bạn. Sử dụng Math.max(1, yourVariable) để đảm bảo bạn không bao giờ truyền số 0 hoặc số âm cho Google.
var targetRow = calculateNextRow();
// Lưới bảo vệ: buộc hàng phải ít nhất là 1
sheet.getRange(Math.max(1, targetRow), 1).activate();
Cách 2: Sử dụng câu lệnh điều kiện (Guard Clauses) cho dữ liệu động
Luôn bao bọc các thao tác vùng của bạn trong một câu lệnh if nếu kích thước dữ liệu có thể thay đổi. Điều này ngăn chặn kịch bản cố gắng xử lý "không có gì".
if (data && data.length > 0) {
sheet.getRange(1, 1, data.length, data[0].length).setValues(data);
} else {
console.warn("Data was empty. Skipping sheet write to prevent crash.");
}
Cách 3: Sử dụng hàm hỗ trợ "Safe Range"
Nếu bạn đang xây dựng một công cụ mà người dùng có thể nhập lượng dữ liệu khác nhau, hãy sử dụng một hàm hỗ trợ để tự động mở rộng kích thước trang tính trước khi lấy vùng dữ liệu.
function getRangeAndExpand(sheet, row, col, numRows, numCols) {
var maxR = sheet.getMaxRows();
var maxC = sheet.getMaxColumns();
// Kiểm tra xem có cần thêm hàng không
if (row + numRows - 1 > maxR) {
sheet.insertRowsAfter(maxR, (row + numRows - 1) - maxR);
}
// Kiểm tra xem có cần thêm cột không
if (col + numCols - 1 > maxC) {
sheet.insertColumnsAfter(maxC, (col + numCols - 1) - maxC);
}
return sheet.getRange(row, col, numRows, numCols);
}
Danh sách kiểm tra xác minh
Để xác định chính xác nguyên nhân, hãy thêm một dòng nhật ký (log) ngay trước khi xảy ra lỗi. Mở tab Executions trong trình soạn thảo Apps Script để xem kết quả.
console.log(`Target: Row ${r}, Col ${c} | Dimensions: ${h}x${w}`);
sheet.getRange(r, c, h, w);
Hãy tìm bất kỳ giá trị nào là 0, số âm hoặc vượt quá các con số hiển thị trong sheet.getMaxRows(). Nếu nhật ký của bạn cho biết bạn đang yêu cầu Hàng 1005 trên một trang tính 1000 hàng, bạn đã tìm thấy "thủ phạm" rồi đó.

