A 400 Bad Request in Google Apps Script means the server rejected your request; fix it by correcting the URL, headers, data, or method.
Hitting a bad request wall in Apps Script usually comes down to malformed inputs or mismatched expectations between your script and the endpoint. The server flags it as invalid and returns 400. In plain terms, something isn’t shaped the way the server expects. MDN’s definition backs this up, listing malformed syntax, invalid framing, or deceptive routing as common reasons.
Bad Request Error 400 Google Apps Script — What It Means
400 signals a client side issue, not a network outage or a server crash. In Apps Script, the “client” can be your web app (doGet or doPost), a trigger calling a Google API, or UrlFetchApp reaching out to another service. Start by inspecting URL, method, headers, body, and size. MDN notes that 400 covers invalid syntax and misframed requests.
You might see a bare 400 page when calling a deployed web app, a JSON error from a Google API, or an exception in UrlFetchApp when the remote endpoint rejects the call. The core idea stays the same: the server declined the shape, period, until the request matches what the endpoint expects.
Common Causes And Quick Checks
Use these checks to catch Bad Request Error 400 Google Apps Script issues.
- Fix the method mismatch — Send data with POST to endpoints that expect POST, and use GET for read-only routes. Web apps in Apps Script expose
doGetanddoPost; match the caller to the handler. - Set the right content type — When returning or sending JSON, stringify the payload and set
ContentService.MimeType.JSONor headerContent-Type: application/json. Skipping this can lead to rejected requests or broken parsing. - Clean up headers — Include only headers the endpoint expects, and be precise with Authorization, Accept, and Content-Type. Apps Script fetches use Google IP ranges; some services require allowlisting.
- Trim oversized inputs — Long URLs and large POST bodies can break requests or cause tight platform limits to fire. Shift long query strings to POST bodies, compress JSON, or page the data.
- Respect quotas and rate limits — Heavy scripts can hit daily UrlFetch quotas and API limits. While quota errors have their own messages, crowding limits can tempt brittle retries that surface as 4xx. Plan calls, cache results, and batch work.
Fix Bad Request 400 In Apps Script: A Step-By-Step Flow
Run this flow when 400 appears. Stop at the first step that clears it.
- Reproduce with a known-good client — Try the same request with curl or a REST client. If that works, inspect differences in method, headers, or body formatting between the client and your script. MDN’s page confirms that tiny formatting slips can trigger 400.
- Log the raw inputs — Print the full URL, method, and a compacted version of the JSON body before each fetch. Avoid writing secrets to logs. In web apps, log
e.parameterande.postData.getDataAsString()to see what arrived. - Use the right handler — If your page submits a form or an integration posts JSON, deploy a web app with a
doPost(e)that readse.postData. Reply withContentService.createTextOutput(JSON.stringify(obj)).setMimeType(ContentService.MimeType.JSON). - Declare headers explicitly — Build an options object for
UrlFetchApp.fetchwithmethod,headers, and, for JSON,payloadas a string pluscontentType. Keep Authorization current. - Shrink the request — Move huge query params into the POST body, remove nulls, and send only the fields the API accepts. Long URLs can fail; POST bodies can also exceed limits. Split large transfers or send files in chunks.
- Check allowlists and redirects — Some services block unknown IPs or non-standard ports. Apps Script calls come from Google IP pools; ask vendors to allowlist them. Avoid sending requests to URLs that force odd redirects.
- Slow down and cache — When volume climbs, cache responses and respect
UrlFetchquotas. Fewer, smarter calls reduce errors and spend.
Reference Patterns For Clean Requests
These patterns keep your calls within spec and easy to debug.
POST JSON With UrlFetchApp
const url = 'https://api.service.com/v1/resource';
const body = JSON.stringify({id: 123, name: 'Sample'});
const res = UrlFetchApp.fetch(url, {
method: 'post',
contentType: 'application/json',
payload: body,
muteHttpExceptions: true
});
Logger.log(res.getResponseCode());
Logger.log(res.getContentText());
This matches what many APIs expect: POST, JSON body, and Content-Type. The official reference outlines headers and options.
Serve JSON From A Web App
function doPost(e) {
const data = JSON.parse(e.postData.contents || '{}');
const reply = {ok: true, got: data};
return ContentService
.createTextOutput(JSON.stringify(reply))
.setMimeType(ContentService.MimeType.JSON);
}
Stringify the object and set the JSON MIME type so clients parse it right, reliably. That combo is shown in Google’s guide.
Symptoms, Likely Causes, And Fixes
Map the symptom to a likely cause and remedy.
| Symptom | Likely Cause | Fast Fix |
|---|---|---|
| 400 after a form POST | Handler missing or wrong method | Deploy a web app with doPost(e); parse e.postData. |
| 400 with JSON API | Wrong Content-Type or un-stringified body |
Send application/json; JSON.stringify the payload. |
| 400 only in Apps Script | Headers differ from curl or client | Compare and align method, headers, and body fields. |
| 400 when URL is long | Query string too large | Move params into POST body; page the request. |
| Intermittent 4xx/5xx | Quota pressure or bursts | Cache responses; batch and space calls. |
| 400 from private API | IP not allowlisted or odd port | Allowlist Google fetch IPs; use standard ports. |
Bad Request 400 In Google Apps Script — Extra Tips That Save Time
- Send smaller chunks — Break big uploads into parts or compress JSON before sending. Large payloads are a common trouble spot.
- Prefer simple ASCII first — If the body includes high-byte characters, send a plain test payload to see if encoding is the trigger. Many APIs expect UTF-8.
- Echo back inputs — In your web app, print request details to the response in test builds. That proves what the server saw.
- Flip
muteHttpExceptionson — Capture the response body and headers when the server replies with 400. The message often names the missing field exactly. - Compare against docs — Cross-check the API’s required fields and examples. Small naming slips (snake vs camel) often cause rejects.
- Cache and back off — Use
CacheServiceand timeouts to keep duplicate fetches from piling up during spikes. Quotas forUrlFetchAppare listed in Google’s table. - Clear cookie loops — If you hit a 400 page while opening the editor from Docs or Sheets, clear cookies or open the project at
script.google.com; redirect loops can trigger it.
Bad Request Error 400 Google Apps Script — Clean Checklist
Pin this list next to your editor. Running through it usually clears things fast.
- Confirm the endpoint — Is the path correct and live?
- Pick GET or POST — Match the server’s expectation; wire
doGetordoPostto fit. - Shape the JSON —
JSON.stringifythe body; avoid undefined and null clutter. - Declare
Content-Type— Setapplication/jsonfor JSON or the MIME type the API needs. - Trim size — Keep URLs short and bodies lean; split large sends.
- Send only required fields — Drop extras that the API ignores or rejects.
- Pass auth cleanly — Use the header format the API documents; refresh tokens on schedule.
- Test and log — Compare your script to a known-good curl run; log inputs and the 400 response body.
- Watch quotas — Cache, batch, and avoid bursty loops. Check Google’s current quota table.
- Re-deploy the web app — After code changes, deploy a new version and use the fresh URL to avoid stale behavior.
With these steps, you can resolve bad request errors quickly and keep development moving. If you’re still stuck, strip the call down to a minimal repro: a tiny JSON body, one header, and a direct URL. Then add pieces back until the server accepts the shape. That process works for UrlFetchApp and for web apps on doGet/doPost, in test or prod.
If you search for Bad Request Error 400 Google Apps Script again, you should land on this guide. The steps above mirror the way HTTP works and align with Google’s own docs on Content service, UrlFetchApp, and quotas.
