Apps Script Google Sheets Bad Request? Causes & Fixes

How-to basics · Updated November 3, 2026

Apps Script Google Sheets Bad Request? Causes & Fixes

Yes—“Bad Request” in a Google Sheets Apps Script usually means a request was rejected because its URL, range, parameters, or data did not match what the receiving service expects. Find the exact failing call and inspect its HTTP response or execution error before changing code; the message alone does not identify the cause.

What “Bad Request” means

Bad Request is commonly used for HTTP status 400. It indicates that a server received a request but could not process it as sent. In a Sheets automation, the request might go to Google’s Sheets API, another web service called with Apps Script’s UrlFetchApp, or an internal service used by a spreadsheet method. Those situations can produce similar wording while requiring different fixes.

A 400 response is not the same as an authorization error or a quota limit. A malformed range or invalid JSON is a plausible 400 cause; missing permission more often produces a 401 or 403, while too many requests may produce a 429. These are useful clues, not guarantees: services can return different status codes or wrap the underlying error in a less specific Apps Script exception.

Also, “Bad Request” does not automatically mean Google Sheets itself is broken. The fault may be in a script’s input, a constructed URL, or a separate API endpoint. The most useful evidence is the execution record, response code, and response body for the operation that failed.

First identify which call failed

Open the Apps Script project and select Executions in the left-hand navigation. Find the failed run, open its details, and note the function, timestamp, error text, and line number. The line number often points to the call that raised the error, although a helper function or a call several layers earlier may have built the bad input.

Then establish which kind of operation the line performs:

  • SpreadsheetApp reads or edits a spreadsheet through Apps Script’s built-in service.
  • Sheets calls the Advanced Sheets service, which exposes Sheets API operations.
  • UrlFetchApp.fetch() sends an HTTP request to a URL, which could be the Sheets API or an unrelated service.

This distinction matters. A failure from UrlFetchApp can include an HTTP status and response body, while a built-in spreadsheet method may raise a script exception without presenting a raw HTTP response. Do not assume that every error mentioning a spreadsheet is an API request you can inspect in the same way.

Common causes in Sheets scripts

Check the request’s inputs before rewriting the script. Typical causes include:

  • Invalid or incorrectly quoted range: A sheet name containing spaces or punctuation needs correct quoting in A1 notation. For example, a range on a tab named Quarter 1 is written 'Quarter 1'!A1:C10. A misspelled tab name or malformed range can also fail.
  • Wrong spreadsheet ID: A copied URL, an empty variable, or an ID from a different file can send the request to the wrong resource. Confirm that the ID is the portion between /d/ and the next slash in a standard Sheets URL.
  • Malformed JSON: Manually concatenating JSON strings can leave out a comma, quote, bracket, or escape character. Build a JavaScript object and serialize it with JSON.stringify() instead.
  • Invalid request fields or values: An API operation may reject an unsupported field, an incompatible value, or a request body that does not match that operation’s schema.
  • Unencoded URL parameters: Spaces, apostrophes, exclamation marks, and other characters in a range or query parameter can change how a URL is interpreted. Encode variable URL components rather than assembling them unescaped.
  • Unexpected input data: A blank cell, a date object, a nested array with the wrong dimensions, or a value of an unexpected type can make a previously valid request fail.

Do not “fix” a range by changing it to a guessed tab name or by removing characters blindly. Log the actual value at runtime, then compare it with the spreadsheet’s tab names and the API operation’s required format.

Inspect an HTTP response safely

For a request made with UrlFetchApp, setting muteHttpExceptions to true lets the script receive an HTTP error response rather than stopping at a non-success status. The response code and body can then reveal a more specific message. This does not suppress every possible failure: an invalid URL, network problem, or other fetch exception can still throw an error.

function inspectResponse() {
  const url = 'PUT_YOUR_REQUEST_URL_HERE';
  try {
    const response = UrlFetchApp.fetch(url, {
      method: 'get',
      muteHttpExceptions: true
    });
    console.log('HTTP status: ' + response.getResponseCode());
    console.log(response.getContentText());
  } catch (error) {
    console.log('Fetch failed: ' + error.message);
    throw error;
  }
}

Replace the placeholder with the actual URL and use the HTTP method appropriate to that endpoint; a GET example is not a substitute for a required POST or PUT. Avoid logging access tokens, passwords, private spreadsheet contents, or other sensitive data. If the response body is JSON, inspect its error message and details rather than relying only on the first line of the Apps Script exception.

Build API requests from structured data

When calling the Sheets API directly, construct the body as an object and let Apps Script serialize it. For example, this pattern updates a range through the values endpoint. It assumes the Sheets API is enabled for the project and that the executing account has permission to edit the spreadsheet.

function writeValues() {
  const spreadsheetId = 'YOUR_SPREADSHEET_ID';
  const range = "'Quarter 1'!A1:B2";
  const url = 'https://sheets.googleapis.com/v4/spreadsheets/' +
    spreadsheetId + '/values/' + encodeURIComponent(range) +
    '?valueInputOption=USER_ENTERED';
  const body = {
    values: [
      ['Name', 'Count'],
      ['Ada', 3]
    ]
  };

  const response = UrlFetchApp.fetch(url, {
    method: 'put',
    contentType: 'application/json',
    headers: {
      Authorization: 'Bearer ' + ScriptApp.getOAuthToken()
    },
    payload: JSON.stringify(body),
    muteHttpExceptions: true
  });

  console.log(response.getResponseCode());
  console.log(response.getContentText());
}

The range is URL-encoded as one path component, and the JSON body is generated from an object rather than hand-built text. In a real project, verify the OAuth scopes and API setup required by the chosen approach. If you use the Advanced Sheets service instead, add it under Services in the Apps Script editor; that service has its own method signatures, so do not paste a raw REST request body into a method without checking the method’s documentation.

Fix the issue methodically

A small, controlled diagnosis is safer than changing several parts of a script at once. Use this sequence:

  1. Reproduce the failure. Run the same function with the same inputs and identify the first failing line in the execution details.
  2. Log non-sensitive inputs. Record the spreadsheet ID, range, HTTP method, and relevant data shape. For large objects, log a limited sample rather than entire sheet contents.
  3. Validate the target. Open the spreadsheet and confirm the tab exists, the account can access it, and the requested range is valid for the intended operation.
  4. Check the endpoint and method. Confirm that the URL uses the documented API version and resource path, and that GET, POST, PUT, or another method matches the operation.
  5. Check the payload. Serialize objects with JSON.stringify(), verify arrays have the expected dimensions, and remove fields the endpoint does not accept.
  6. Compare with a minimal request. Try the smallest valid operation, then add fields or rows incrementally. This helps isolate which input triggers the rejection.
  7. Retest with the actual account. Permissions, authorization scopes, and available APIs can differ between the person running the script and the person who owns the file.

If you change the script’s OAuth scopes or enable an API, review the authorization prompt and run the function again as the intended user. Avoid repeatedly retrying an unchanged malformed request: retries are useful for transient failures, not for correcting invalid input.

SpreadsheetApp, the Sheets API, and error differences

For ordinary reading and writing in a bound script, SpreadsheetApp is often the simplest choice. It avoids manually assembling HTTP URLs and JSON request bodies. For example, the script can open a spreadsheet by ID and obtain a named sheet before reading a range. You still need to validate that the ID, sheet, and range exist, and Apps Script services have their own quotas and execution limits.

The Advanced Sheets service and the Sheets API are more appropriate when a task needs API features or operations not conveniently handled by the built-in service. They expose explicit request structures, which can make complex updates possible but also means malformed fields and request bodies need careful checking. Direct REST calls with UrlFetchApp offer flexibility, but you take responsibility for endpoint construction, encoding, authentication, and response handling.

These approaches are not interchangeable in every detail. A 400-style HTTP response is especially relevant when an HTTP API call is involved; a built-in service may report a related problem as an Apps Script exception. Use the documentation for the exact method or API endpoint named in the failing line rather than applying a generic “bad request” fix to every case.

When the error may not be a bad request

Read the full error and status code before concluding that the input is malformed. A 401 commonly points to authentication, and a 403 commonly points to insufficient permission, disabled API access, or a restricted operation. A 404 can indicate an incorrect resource ID or endpoint. A 429 suggests a rate or quota limit, while a timeout may mean the service did not respond in time. Exact behavior varies by service, and Apps Script’s own execution limits are separate from HTTP status codes.

If a request worked previously and then began failing, check what changed: the data, the spreadsheet’s sharing settings, the deployed script version, API configuration, or the service’s documented behavior. For a script triggered by an installable trigger, remember that it runs under the account that created the trigger, not necessarily the person whose edit caused it. That can explain permission failures that look like a code problem.

Frequently Asked Questions

Why does Apps Script say “Bad Request” when I write to Google Sheets?
First check the exact range, spreadsheet ID, request body, and operation. If the script uses the Sheets API or UrlFetchApp, inspect the HTTP status and response body; if it uses SpreadsheetApp, use the execution details and validate the method’s inputs.

Does Bad Request mean my Google Sheets API quota is exceeded?
Not usually. A quota or rate limit is commonly reported as 429, while 400 more often points to a request the service cannot accept. Check the response details because status codes and error wording can vary.

How do I see the full error from UrlFetchApp?
Set muteHttpExceptions: true in the fetch options, then log getResponseCode() and getContentText(). Keep credentials and private data out of logs, and still use try/catch for errors that happen before an HTTP response is returned.

Can an invalid sheet name cause a 400 error?
Yes, when the name is used in a range sent to an API, a misspelled or incorrectly quoted name can make the request invalid. Quote names with spaces or special characters in A1 notation and URL-encode the range when placing it in a URL.

Should I use SpreadsheetApp or the Sheets API?
Use SpreadsheetApp for straightforward spreadsheet reads and edits when its methods meet the need. Consider the Advanced Sheets service or the REST API for operations requiring their specific capabilities, while accounting for setup, authorization, and request-format requirements.

Related

Try it: the Date Difference Calculator: days, months, years and weekdays between two dates, with the DATEDIF formulas.

More in How-to basics

Sources: Function behaviour and menu paths: Microsoft Support documentation for Excel. Method & sources

Spotted an error in this guide? Let us know.