问题
The Q&A is currently a subject of meta discussion - please, do participate. Current plan is to split where possible (and no canonicals exist) into separate Q&As. The answer to the question is a community wiki and the question intended to become one when the status of the Q&A itself is resolved.
Preface
This Q&A strives to become a collection and a reference target for common errors encountered during development in Google Apps Script language in hopes to improve long-term maintainability of google-apps-script tag.
There are several similar and successful undergoings in other languages and general-purpose tags (see c++, android, php, php again), and this one follows suit.
Why it exists?
The amount of questions from both new and experienced developers regarding the meaning and solutions to errors encountered during development and production that can be effectively reduced to a single answer is substantial. At the time of writing, even running a query only by language tag yields:
- "Cannot find method" 8 pages
- "Cannot read property" 9 pages
- "Cannot call ... in this context" 5 pages
- "You do not have permission" 11 pages
Linking to a most relevant duplicate is hard and time-consuming for volunteers due to the need to consider nuances and often poorly-worded titles.
What it consists of?
Entries in this Q&A contain are designed as to provide info on how to:
- parse the error message structure
- understand what the error entails
- consistently reproduce (where applicable)
- resolve the issue
- provide a link to canonical Q&A (where possible)
What this is not?
The scope of the Q&A is limited to common (not trivial). This is not:
- a catch-all guide or "best practices" collection
- a reference for general ECMAScript errors
- GAS documentation
- a resources list (we have a tag wiki for that)
What to add?
When adding an entry, please, consider the following:
- is the error common enough (see "why" section for examples)?
- can the solution be described concisely and be applicable for most cases?
回答1:
Preface
The initial answer provides a guide on general and built-in service-related errors.
Entries addressing issues with services listed in official reference are welcome.
This is an ongoing project and will be constantly updated.
General errors
Message
TypeError: Cannot read property '
property name here
' fromundefined (or null)
Description
The error message indicates that you are trying to access a property on an Object
instance, but during runtime the value actually held by variable is a special data type undefined
. Typically, the error occurres when accessing nested properties of an object.
A variation of this error with numeric value in place of property name indicates that an instance of Array
was expected. As arrays in JavaScript are objects, everything mentioned here is true about them as well.
There is a special case of dynamically constructed objects such as event objects that are only available in specific contexts like making an HTTP request to the app or invoking a function via time or event-based trigger.
The error is a TypeError because an
"object"
is expected, but"undefined"
is received
How to fix
Using default values
Logical OR||
operator in JavaScript has an intersting property of evaluating the right-hand side iff the left-hand is falsy. Since objects in JS are truthy, andundefined
andnull
are falsy, an expression like(myVar || {}).myProp
[(myVar || [])[index]
for arrays] will guarantee that no error is thrown and the property is at leastundefined
.
One can also provide default values:(myVar || { myProp : 2 })
guarantees accessingmyProp
to return2
by default. Same goes for arrays:(myVar || [1,2,3])
.Checking for type
Especially true for the special case,typeof
operator combined with anif
statement and a comparison operator will either allow a function to run outside of its designated context (i.e. for debugging purposes) or introduce branching logic depending on whether the object is present or not.
One can control how strict the check should be:- lax ("not undefined"):
if(typeof myVar !== "undefined") { //do something; }
- strict ("proper objects only"):
if(typeof myVar === "object" && myVar) { //do stuff }
- lax ("not undefined"):
Related Q&As
- Parsing order of GAS project as the source of the issue
Message
Cannot convert
some value
todata type
Description
The error is thrown due to passing an argument of different type than a method expects. Common mistake that causes the error is an accidental coercion of a number to string.
How to reproduce
function testConversionError() {
const ss = SpreadsheetApp.getActiveSheet();
ss.getRange("42.0",1);
}
How to fix
Make sure that the value referenced in the error message is of data type required by documentation and convert as needed.
Message
Cannot call
Service and method name
from this context
Description
This error happens on a context mismatch and is specific to container-bound scripts.
Primary use case that results in the error is trying to call a method only available in one document type (usually, getUi()
as it is shared by several services) from another (i.e. DocumentApp.getUi()
from a spreadsheet).
Secondary, but also prominent case is a result of calling a service not explicitly allowed to be called from a custom function (usually a function marked by special JSDoc-style comment @customfunction
and used as a formula).
How to reproduce
For bound script context mismatch, declare and run this function in a script project tied to Google Sheets (or anything other than Google Docs):
function testContextMismatch() {
const doc = DocumentApp.getUi();
}
Note that calling a DocumentApp.getActiveDocument()
will simply result in null
on mismatch, and the execution will succeed.
For custom functions, use the function declared below in any cell as a formula:
/**
* @customfunction
*/
function testConversionError() {
const ui = SpreadsheetApp.getUi();
ui.alert(`UI is out of scope of custom function`);
}
How to fix
- Context mismatch is easily fixed by changing the service on which the method is called.
- Custom functions cannot be made to call these services, use custom menus or dialogs.
Message
Cannot find method
Method name here
The parameters
param names
do not match the method signature formethod name
Description
This error has a notoriously confusing message for newcomers. What it says is that a type mismatch occurred in one or more of the arguments passed when the method in question was called.
There is no method with the signature that corresponds to how you called it, hence "not found"
How to fix
The only fix here is to read the documentation carefully and check if order and inferred type of parameters are correct (using a good IDE with autocomplete will help). Sometimes, though, the issue happens because one expects the value to be of a certain type while at runtime it is of another. There are several tips for preventing such issues:
- Setting up type guards (
typeof myVar === "string"
and similar). - Adding a validator to fix the type dynamically thanks to JavaScript being dynamically typed.
Sample
/**
* @summary pure arg validator boilerplate
* @param {function (any) : any}
* @param {...any} args
* @returns {any[]}
*/
const validate = (guard, ...args) => args.map(guard);
const functionWithValidator = (...args) => {
const guard = (arg) => typeof arg !== "number" ? parseInt(arg) : arg;
const [a,b,c] = validate(guard, ...args);
const asObject = { a, b, c };
console.log(asObject);
return asObject;
};
//driver IIFE
(() => {
functionWithValidator("1 apple",2,"0x5");
})()
Messages
You do not have permission to perform that action
The script does not have permission to perform that action
Description
The error indicates that one of the APIs or services accessed lacks sufficient permissions from the user. Every service method that has an authorization section in its documentation requires at least one of the scopes to be authorized.
As GAS essentially wraps around Google APIs for development convenience, most of the scopes listed in OAuth 2.0 scopes for APIs reference can be used, although if one is listed in the corresponding docs it may be better to use it as there are some inconsistencies.
Note that custom functions run without authorization. Calling a function from a Google sheet cell is the most common cause of this error.
How to fix
If a function calling the service is ran from the script editor, you are automatically prompted to authorize it with relevant scopes. Albeit useful for quick manual tests, it is best practice to set scopes explicitly in application manifest (appscript.json). Besides, automatic scopes are usually too broad to pass the review if one intends to publish the app.
The field oauthScopes
in manifest file (View -> Show manifest file
if in code editor) should look something like this:
"oauthScopes": [
"https://www.googleapis.com/auth/script.container.ui",
"https://www.googleapis.com/auth/userinfo.email",
//etc
]
For custom functions, you can fix it by switching to calling the function from a menu or a button as custom functions cannot be authorized.
For those developing editor Add-ons this error means an unhandled authorization lifecycle mode: one has to abort before calls to services that require authorization in case auth mode is AuthMode.NONE
.
Related causes and solutions
@OnlyCurrentDoc
limiting script access scope- Scopes autodetection
Message
ReferenceError:
service name
is not defined
Description
The most common cause is using an advanced service without enabling it. When such a service is enabled, a variable under the specified identifier is attached to global scope that the developer can reference directly. Thus, when a disabled service is referenced, a ReferenceError
is thrown.
How to fix
Go to "Resources -> Advanced Google Services" menu and enable the service referenced. Note that the identifier should equal the global variable referenced. For more detailed explanation, read the official guide.
If one hasn't referenced any advanced services then the error points to an undeclared variable being referenced.
Message
The script completed but did not return anything.
Script function not found:
doGet or doPost
Description
This is not an error per se (as the HTTP response code returned is 200
and the execution is marked as successful, but is commonly regarded as one. The message appears when trying to make a request / access from browser a script deployed as a Web App.
There are two primary reasons why this would happen:
- There is no
doGet
ordoPost
trigger function - Triggers above do not return an
HtmlOutput
orTextOutput
instance
How to fix
For the first reason, simply provide a doGet
or doPost
trigger (or both) function. For the second, make sure that all routes of your app end with creation of TextOutput or HtmlOutput:
//doGet returning HTML
function doGet(e) {
return HtmlService.createHtmlOutput("<p>Some text</p>");
}
//doPost returning text
function doPost(e) {
const { parameters } = e;
const echoed = JSON.stringify(parameters);
return ContentService.createTextOutput(echoed);
}
Note that there should be only one trigger function declared - treat them as entry points to your application.
If the trigger relies on parameter
/ parameters
to route responses, make sure that the request URL is structured as "baseURL
/exec?query
" or "baseURL
/dev?query
" where query
contains parameters to pass.
Related Q&As
- Redeploying after declaring triggers
Message
We're sorry, a server error occurred. Please wait a bit and try again.
Description
This one is the most cryptic errors and can occur at any point with nearly any service (although DriveApp
usage is particularly susceptible to it). The error usually indicates a problem on Google's side that either goes away in a couple of hours / days or gets fixed in the process.
How to fix
There is no silver bullet for that one and usually there is nothing you can do apart from filing an issue on issue tracker or contacting support if you have a GSuite account. Before doing that one can try the following common remedies:
- For bound scripts - creating a new document and copying over the existing project and data.
- Switch to using an advanced
Drive
service (always remember to enable it first). - There might be a problem with a regular expression if the error points to a line with one.
Don't bash your head against this error - try locating affected code, file or star an issue and move on
Syntax error without apparent issues
This error is likely to be caused by using an ES6 syntax (for example, arrow functions) while using the deprecated V8 runtime (at the time of writing GAS platform uses V8).
How to fix
Open "appscript.json" manifest file and check if runtimeVersion
is set to "V8"
, change it if not or remove any ES6 features otherwise.
Quota-related errors
There are several errors related to quotas imposed on service usage. Google has a comprehensive list of those, but as a general rule of thumb, if a message matches "too many" pattern, you are likely to have exceeded the respective quota.
Most likely errors encountered:
- Service invoked too many times:
service name
- There are too many scripts running
- Service using too much computer time for one day
- This script has too many triggers
How to fix
In most cases, the only fix is to wait until the quota is refreshed or switch to another account (unless the script is deployed as a Web App with permission to "run as me", in which case owner's quotas will be shared across all users).
To quote documentation at the time:
Daily quotas are refreshed at the end of a 24-hour window; the exact time of this refresh, however, varies between users.
Note that some services such as MailApp
have methods like getRemainingDailyQuota that can check the remaining quota.
In the case of exceeding maximum number of triggers one can check how many are installed via getProjectTriggers() (or check "My triggers" tab) and act accordingly to reduce the number (for example, by using deleteTrigger(trigger) to get rid of some).
Related canonical Q&As
- How are daily limitations being applied and refreshed?
- "Maximum execution time exceeded" problem
- Optimizing service calls to reduce execution time
Service-specific errors
SpreadsheetApp
Message
The number of
rows or cells
in the data does not match the number ofrows or cells
in the range. The data hasN
but the range hasM
.
Description
The error points to a mismatch in dimensions of range in relation to values. Usually, the issue arises when using setValues()
method when the matrix of values is smaller or bigger than the range.
How to reproduce
function testOutOfRange() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sh = ss.getActiveSheet();
const rng = sh.getActiveRange();
const vals = rng.getValues();
try {
vals.push([]);
rng.setValues(vals);
} catch (error) {
const ui = SpreadsheetApp.getUi();
ui.alert(error.message);
}
}
How to fix
If it is routinely expected for values to get out of bounds, implement a guard that catches such states, for example:
const checkBounds = (rng, values) => {
const targetRows = rng.getHeight();
const targetCols = rng.getWidth();
const { length } = values;
const [firstRow] = values;
return length === targetRows &&
firstRow.length === targetCols;
};
Message
The coordinates of the range are outside the dimensions of the sheet.
Description
The error is a result of collision between two issues:
- The
Range
is out of bounds (getRange()
does not throw on requesting a non-existent range) - Trying to call a method on a
Range
instance referring to a non-existent dimension of the sheet.
How to reproduce
function testOB() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sh = ss.getActiveSheet();
const rng = sh.getRange(sh.getMaxRows() + 1, 1);
rng.insertCheckboxes();
}
How to fix
Check that number of rows (getMaxRow()) and columns (getMaxColumns()) are both greater or equal to the parameters passed to getRange()
method call and change them accordingly.
UrlFetchApp
Message
Attribute provided with no value: url
Description
The error is specific to UrlFetchApp
service and happens when fetch
or fetchAll
method gets called with an empty string or non-string value.
How to reproduce
const response = UrlFetchApp.fetch("", {});
How to fix
Make sure that a string containing a URI (not necessarily valid) is passed to the method as its first argument. As its common root cause is accessing a non-existent property on an object or array, check whether your accessors return an actual value.
References
- How to make error messages more meaningful
- Debugging custom functions
来源:https://stackoverflow.com/questions/62336082/how-to-solve-common-errors-in-google-apps-script-development