Hướng dẫn

Sửa Lỗi Bad Request Error 400 Trong Apps Script Google Sheets 2026

Tuân HoangTuân Hoang
5 tháng 8, 2026
Cập nhật: 11 tháng 8, 2026
9 phút đọc
Ảnh minh họa bài viết: Sửa Lỗi Bad Request Error 400 Trong Apps Script Google Sheets 2026

Lỗi Bad Request (400) trong Apps Script Google Sheets thường xuất hiện khi bạn gọi UrlFetchApp.fetch() tới một API bên ngoài, gọi Google API (Sheets API, Gmail API, Calendar API...), hoặc deploy Web App và test bằng doGet/doPost. Thông báo lỗi khá chung chung — chỉ nói "Bad Request" mà không chỉ rõ tham số nào sai — nên phần lớn thời gian debug bị tốn vào việc đoán mò. Bài này liệt kê các nguyên nhân phổ biến nhất và cách xử lý từng trường hợp, dựa trên các case thực tế khi build script quản lý dữ liệu, gửi email, gọi API cho SME.

Nguyên nhân phổ biến gây lỗi 400 trong Apps Script

Trước khi sửa, cần xác định lỗi 400 xảy ra ở đâu. Có 3 nhóm tình huống chính:

  • Gọi Google API nội bộ (Sheets API v4, Gmail API, Drive API...) qua UrlFetchApp hoặc Advanced Services — sai format request body, thiếu scope, hoặc range/spreadsheetId không hợp lệ.
  • Gọi API bên thứ ba (webhook, CRM, payment gateway...) — sai Content-Type, JSON malformed, thiếu header bắt buộc.
  • Web App tự deploy (doGet/doPost) — client gửi request sai format, hoặc CORS/redirect làm method bị đổi.

Mỗi nhóm có cách debug khác nhau, nên việc đầu tiên là log lại toàn bộ response body của lỗi thay vì chỉ đọc message "Bad Request".

Cách lấy chi tiết lỗi thay vì chỉ thấy "400"

Mặc định khi UrlFetchApp.fetch() gặp lỗi, Apps Script sẽ throw exception và dừng script — bạn không thấy được nội dung response. Cách khắc phục là dùng muteHttpExceptions: true:

function callApi() {
  var options = {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify({ key: 'value' }),
    muteHttpExceptions: true // bắt buộc để đọc được response lỗi
  };
  var response = UrlFetchApp.fetch('https://api.example.com/endpoint', options);
  Logger.log('Status: ' + response.getResponseCode());
  Logger.log('Body: ' + response.getContentText());
}

Khi có muteHttpExceptions: true, response 400 sẽ trả về bình thường thay vì throw lỗi, và getContentText() thường chứa message cụ thể từ server (ví dụ "Missing required field: email" hoặc "Invalid range"). 90% trường hợp mình gặp, chỉ cần đọc kỹ body này là biết ngay nguyên nhân.

Lỗi 400 khi gọi Google Sheets API v4

Đây là nhóm phổ biến nhất khi bạn dùng Sheets.Spreadsheets.Values.update() hoặc gọi trực tiếp REST API qua UrlFetchApp.

Sai định dạng range (A1 notation)

Lỗi thường gặp: Unable to parse range: Sheet1!A1:B. Nguyên nhân là range thiếu số dòng kết thúc hoặc tên sheet chứa ký tự đặc biệt (dấu cách, tiếng Việt có dấu) mà không được bọc trong dấu nháy đơn.

// Sai — tên sheet có dấu cách không bọc nháy đơn
var range = "Báo cáo tháng!A1:D10";

// Đúng
var range = "'Báo cáo tháng'!A1:D10";

Body request sai cấu trúc

Khi dùng Values.update, body bắt buộc phải có field values là mảng 2 chiều, kể cả khi chỉ update 1 ô:

// Sai
var resource = { values: "Hello" };

// Đúng
var resource = { values: [["Hello"]] };

Sheets.Spreadsheets.Values.update(resource, spreadsheetId, range, { valueInputOption: 'USER_ENTERED' });

Thiếu tham số valueInputOption (phải là RAW hoặc USER_ENTERED) cũng gây 400 — đây là tham số bắt buộc với API v4, khác với v3 cũ.

Bảng lỗi thường gặp khi gọi Sheets API

Thông báo lỗiNguyên nhânCách sửa
Unable to parse rangeSai cú pháp A1 notation, tên sheet có ký tự đặc biệtBọc tên sheet trong dấu nháy đơn
Invalid JSON payload receivedBody không phải JSON hợp lệ (thừa dấu phẩy, thiếu ngoặc)Validate JSON bằng JSON.stringify() trước khi log ra kiểm tra
Missing valueInputOptionThiếu tham số bắt buộc khi update giá trịLuôn truyền RAW hoặc USER_ENTERED
Requested writing within range that has a larger dimensionSố dòng/cột trong values không khớp range khai báoĐếm lại số phần tử mảng khớp với range

Nếu bạn đang xây các công thức nâng cao kết hợp Apps Script để đẩy/kéo dữ liệu giữa nhiều sheet, tham khảo thêm hướng dẫn Google Sheets nâng cao về ARRAYFORMULA, QUERY, IMPORTRANGE và Apps Script để hiểu rõ cách dữ liệu di chuyển giữa các range, giúp tránh sai lệch cấu trúc dẫn tới lỗi 400.

Lỗi 400 khi gọi API bên thứ ba qua UrlFetchApp

Khi tích hợp với CRM, webhook, hoặc dịch vụ gửi email/SMS ngoài, lỗi 400 gần như luôn do 1 trong 4 nguyên nhân sau.

1. Content-Type không khớp với payload

Nhiều API yêu cầu application/json nhưng Apps Script mặc định gửi application/x-www-form-urlencoded nếu bạn không set rõ:

var options = {
  method: 'post',
  contentType: 'application/json', // BẮT BUỘC khai báo rõ
  payload: JSON.stringify(data),
  muteHttpExceptions: true
};

2. Payload là object thay vì JSON string

Lỗi cực kỳ hay gặp: quên gọi JSON.stringify(), khiến Apps Script tự serialize theo kiểu form-data thay vì JSON đúng chuẩn mà API mong đợi.

3. Header xác thực (Authorization) sai định dạng

Với Bearer token, thiếu chữ "Bearer " phía trước hoặc thừa khoảng trắng cũng khiến server trả 400 (một số API trả 401 nhưng nhiều API custom lại trả 400 cho lỗi auth).

var options = {
  method: 'post',
  contentType: 'application/json',
  headers: {
    'Authorization': 'Bearer ' + apiToken // chú ý dấu cách sau "Bearer"
  },
  payload: JSON.stringify(data),
  muteHttpExceptions: true
};

4. Dữ liệu ngày tháng hoặc số không đúng kiểu

Khi lấy giá trị từ Sheet bằng getValue(), ô ngày tháng trả về đối tượng Date của Apps Script, không phải string ISO 8601 mà hầu hết API yêu cầu. Gửi thẳng object Date vào JSON sẽ ra định dạng lạ và bị API từ chối:

var rawDate = sheet.getRange('A2').getValue(); // trả về Date object
var isoDate = Utilities.formatDate(rawDate, 'GMT+7', "yyyy-MM-dd'T'HH:mm:ssXXX");

Đây là lỗi mình từng gặp khi build hệ thống tự động gửi email nhắc thanh toán — dữ liệu ngày đến hạn lấy từ Sheet không được format trước khi gửi cho service email, gây lỗi 400 liên tục. Chi tiết cách xử lý ngày tháng và trigger email đúng lịch có trong bài Tự Động Gửi Email Nhắc Nhở Thanh Toán Từ Google Sheets bằng Apps Script.

Lỗi 400 khi deploy Web App (doGet/doPost)

Nếu bạn build Web App nhận request từ form HTML, Zapier, hoặc app khác gọi vào, lỗi 400 phía client thường không phải do Apps Script trả về mà do cách gọi sai.

Redirect làm mất method POST

Web App Apps Script luôn trả về HTTP 302 redirect tới URL thực thi (dạng script.googleusercontent.com). Một số client (đặc biệt là fetch API mặc định của trình duyệt hoặc thư viện HTTP cứng nhắc) không tự động follow redirect với method POST, dẫn đến request thứ 2 bị gửi sai cách và server đích trả 400.

Cách kiểm tra: dùng curl -v hoặc Postman với chế độ "follow redirects" bật rõ ràng, xem request cuối cùng thực sự gửi đi có đúng method và body không.

doPost nhận request nhưng e.postData rỗng

Nếu client gửi Content-Type: application/json nhưng không đúng chuẩn, e.postData.contents trong doPost(e) có thể bị rỗng hoặc parse lỗi:

function doPost(e) {
  try {
    if (!e.postData || !e.postData.contents) {
      return ContentService.createTextOutput(
        JSON.stringify({ error: 'No data received' })
      ).setMimeType(ContentService.MimeType.JSON);
    }
    var data = JSON.parse(e.postData.contents);
    // xử lý data...
  } catch (err) {
    Logger.log('Parse error: ' + err.message);
    return ContentService.createTextOutput(
      JSON.stringify({ error: 'Invalid JSON: ' + err.message })
    ).setMimeType(ContentService.MimeType.JSON);
  }
}

Luôn wrap logic parse trong try/catch và trả về message lỗi cụ thể — điều này giúp bên gọi API biết chính xác vấn đề thay vì chỉ thấy "Bad Request" chung chung. Nếu Web App của bạn cần gọi thêm các API ngoài để xử lý dữ liệu (ví dụ enrich thông tin trước khi ghi vào Sheet), phần xử lý JSON và web app trong bài về Apps Script nâng cao — API Calls, JSON và Web App đi sâu hơn vào pattern này.

Quota, scope và giới hạn — nguyên nhân 400 dễ bị bỏ qua

Không phải lỗi 400 nào cũng do sai cú pháp. Một số trường hợp thực chất là do:

  • Thiếu OAuth scope: Nếu script dùng Advanced Google Services (Sheets API, Gmail API...) nhưng file appsscript.json chưa khai báo đủ scope, một số request bị chặn với lỗi trông giống 400 thay vì 403. Kiểm tra bằng cách vào Project Settings → bật "Show appsscript.json manifest file" và xem mảng oauthScopes.
  • Payload vượt giới hạn kích thước: UrlFetchApp giới hạn payload khoảng 50MB, nhưng nhiều API bên thứ ba giới hạn thấp hơn nhiều (thường 1-10MB). Nếu bạn gửi kèm file đính kèm base64 hoá, kiểm tra kích thước trước khi gửi.
  • Batch request quá nhiều item cùng lúc: Với Sheets API, gọi batchUpdate với hàng nghìn request trong 1 lần gọi cũng có thể bị từ chối. Nên chia nhỏ thành các batch 100-500 item.

Với các hệ thống cần xử lý dữ liệu lớn kiểu này — ví dụ đồng bộ danh sách nhân viên mới, import hàng loạt — nguyên tắc chia nhỏ batch và validate trước khi gửi cũng được áp dụng trong Hệ Thống Onboarding Nhân Viên Mới Bằng Google Sheets & Apps Script, đáng tham khảo nếu bạn đang build quy trình tương tự.

Quy trình debug 400 nhanh gọn

Khi gặp lỗi 400 mà chưa biết bắt đầu từ đâu, làm theo thứ tự sau thay vì đoán mò từng dòng code:

  1. Thêm muteHttpExceptions: true vào mọi lệnh gọi UrlFetchApp.fetch() đang nghi ngờ, log cả status code và body.
  2. Copy JSON payload ra một tool validate JSON (hoặc JSON.parse(JSON.stringify(payload)) trong chính script) để chắc chắn không có lỗi cú pháp.
  3. Kiểm tra Content-Type header có khớp với payload thực tế không (JSON vs form-data).
  4. Với Google API: xác nhận range, spreadsheetId, và các tham số bắt buộc (như valueInputOption) đều đầy đủ.
  5. Test lại request y hệt bằng Postman/curl độc lập với Apps Script — nếu Postman cũng lỗi 400, vấn đề nằm ở phía API/dữ liệu, không phải do Apps Script.
  6. Nếu vẫn không ra, log toàn bộ options object (đã stringify) trước khi gửi để so sánh với tài liệu API chính thức từng field một.

Phần lớn thời gian, lỗi 400 nằm ở bước 2 hoặc bước 4 — dữ liệu gửi đi không đúng "hình dạng" mà server mong đợi, chứ không phải lỗi logic phức tạp. Việc log response body ngay từ đầu (thay vì để script throw exception im lặng) tiết kiệm rất nhiều thời gian debug.

Câu hỏi thường gặp

Lỗi Bad Request Error 400 trong Apps Script là gì?

Đây là lỗi HTTP cho biết yêu cầu (request) gửi đến server hoặc API không hợp lệ — thường do sai cú pháp URL, thiếu tham số bắt buộc, payload JSON sai định dạng, hoặc header không đúng khi dùng UrlFetchApp hoặc gọi Sheets API/Advanced Services trong Apps Script.

Nguyên nhân phổ biến nhất gây lỗi 400 khi dùng UrlFetchApp là gì?

Thường do payload gửi đi (JSON.stringify sai cấu trúc), thiếu contentType 'application/json', sai method (GET thay vì POST), hoặc truyền sai range/spreadsheetId khi gọi Sheets API. Nên console.log() toàn bộ options trước khi fetch để kiểm tra.

Làm sao debug lỗi 400 hiệu quả trong Apps Script?

Bọc UrlFetchApp trong try-catch, thêm muteHttpExceptions: true để lấy nội dung response lỗi chi tiết thay vì chỉ thấy exception chung chung, sau đó Logger.log() response.getContentText() để đọc chính xác thông báo lỗi từ server trả về.

Lỗi 400 có phải luôn do code Apps Script sai không?

Không hẳn. Nhiều trường hợp lỗi 400 đến từ phía API bên thứ ba (sai API key, endpoint đã đổi, giới hạn quota) hoặc quyền OAuth scope chưa được cấp đủ trong Apps Script, nên cần kiểm tra cả hai phía trước khi kết luận.

Bạn muốn áp dụng ngay mà không phải tự xây từ đầu?

Khám phá các mẫu Google Sheets và phần mềm quản lý dựng sẵn cho doanh nghiệp Việt tại SheetStore Marketplace.

Chia sẻ bài viết:

Tuân Hoang

Tuân Hoang

Đội ngũ SheetStore

Google SheetsGoogle Apps ScriptCRMAutomationPhần mềm quản lý doanh nghiệp

Google Workspace Certified, 5+ years experience

Bạn thấy bài viết hữu ích?

Đăng ký nhận thông báo khi có bài viết mới.

Nhận thông báo khi có bài viết mới. Không spam, hứa luôn! 😊

Bình luận (0)

Vui lòng đăng nhập để tham gia thảo luận