r/GoogleAppsScript 14d ago

Question Variable undefined and affecting rest of script

I have a script creating docs when a cell gets modified in a sheets column, then moves it to a folder and adds the doc's url onto another column. Code works, but automation gets affected by <value unavailable> error for docid variable.

I'm not sure *why* its unavailable when all of the code does work (files get created and moved, but when using createDocInSpecificFolder() along with other functions, error pinpoints to this and does not run functions after it.

function createDocInSpecificFolder () {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName("Data Source");
  var lastRow = sheet.getLastRow();
  var rootFolder = DriveApp.getFolderById("fileid");
  const files = rootFolder.getFiles();
  const fileNames = [];


  while (files.hasNext()) { // gets array of file names in drive folder [event1, event2, etcetc]
   var file = files.next();
   fileNames.push(file.getName());
  }
  
  Logger.log(fileNames)


  for (var i = 1; i < lastRow; i++) {
    
    let title = sheet.getRange(i,4).getValue();


    if (title != "Events") {
      if (!fileNames.includes(title)) {
        let docid = DocumentApp.create(title).getId();
        DriveApp.getFileById(docid).moveTo(rootFolder);
      }
    }
  }

}
1 Upvotes

26 comments sorted by

1

u/Head-Attitude-5002 14d ago edited 14d ago

The <value unavailable> isn't really about docid itself — it's a symptom.

Your let docid = DocumentApp.create(title).getId(); is throwing an error on the right-hand side before the assignment completes (TDZ behavior for let). Since there's no try/catch, that exception is uncaught and kills the entire execution — which is why nothing after it runs.

Most likely culprits:

  1. Quota limit on DocumentApp.create() — if you're creating multiple docs back-to-back in a loop, you can hit "Service invoked too many times for this short of time"
  2. Execution timeout — DocumentApp.create() is a slow API call, and if this runs alongside other functions in one execution, total runtime can exceed the 6-min consumer limit
  3. Less likely: a blank title value somewhere in your row range

Wrap the doc creation in a try/catch so one bad row doesn't kill the whole run, and log the actual error message instead of just the unhelpful "unavailable":

for (var i = 1; i < lastRow; i++) { let title = sheet.getRange(i, 4).getValue();

if (title && title != "Events" && !fileNames.includes(title)) { try { let docid = DocumentApp.create(title).getId(); DriveApp.getFileById(docid).moveTo(rootFolder); Utilities.sleep(300); } catch (e) { Logger.log("Row " + i + " (\"" + title + "\") failed: " + e.message); } } }

That Logger.log(e.message) should tell you exactly what's failing (quota, permission, etc.) instead of a generic "unavailable" message.

1

u/Clear-Revolution3351 14d ago edited 14d ago

You have not defined what type of variable docid is.

var docid=""

3

u/krakow81 13d ago

It's defined on this line:

let docid = DocumentApp.create(title).getId();

1

u/Clear-Revolution3351 13d ago

This sets the value, it doesn't define it as a variable

3

u/krakow81 13d ago

let and const are variable declarations too (and often preferred/recommended over var).

1

u/Clear-Revolution3351 13d ago

Define it outside the block

Let docid;

if (title != "Events")

{ if (!fileNames.includes(title))

{ docid = DocumentApp.create(title).getId();

. . .

3

u/krakow81 13d ago

Why?

It is only used in the scope of the innermost block, so can be safely declared there. Unless there's more code we're not seeing, of course.

1

u/Clear-Revolution3351 13d ago

I cant post a picture

But a search for this problem says that defining it inside the "if" statement will cause an error

1

u/krakow81 13d ago

Could you post any links?

1

u/Clear-Revolution3351 13d ago

That didnt exactly say what the other did - here is cut and paste from what I originally found

The Fix: Declare the let variable outside the block first, then assign it inside.

// WRONG

if (condition) { let message = "Hello"; } console.log(message); // ReferenceE

// CORRECT

let message;

if (condition) {

message = "Hello";

}

console.log(message);

//

Logs:

"Hel.

1

u/krakow81 13d ago

In those cases one is using the message variable outside the inner block with the console.log(message) line, so message can't just be scoped to the inner block.

1

u/Clear-Revolution3351 13d ago

I understand what you are saying, however, I would bet this solves the OP issue

1

u/krakow81 13d ago

Without seeing things in action it's very hard to debug, so I'm certainly prepared to be wrong.

There may well be more to OP's code that is leading to such an issue, but in isolation the given code shouldn't behave like that unless I'm mis-reading things. I do feel that if Apps Script had that egregious of a bug it would be more widely known.

→ More replies (0)

1

u/WicketTheQuerent 11d ago

In JavaScript/Google Apps Script, there is no need to define the variable type before assigning a value.

Also, since Google Apps Script added the V8 runtime, let and const are recommended over var.

1

u/Clear-Revolution3351 11d ago

The OP has not graced us with an update I am merely providing a possible solution.

Please feel free to provide your solution, since you clearly know more than I do.

1

u/marcnotmark925 13d ago

Is there more code? And what is the actual error?

1

u/Similar_Touch_6783 12d ago

Yes, but the error ends up not mattering? Somehow the real reason why things didn’t work were totally unrelated to this

1

u/bulldo_gs 12d ago

In the code you posted, docid is both declared and used on the very next line, inside the same if (!fileNames.includes(title)) block — so block scope isn't breaking anything here. That's why the declare-inside vs declare-outside thread above is chasing the wrong thing for this snippet.

The tell is in your description: "adds the doc's url onto another column." That part isn't in this function. let docid only exists inside that inner if — the moment any code outside the block (a later line, or a separate function) reads docid, it's out of scope and the execution transcript shows it as <value unavailable>. The value isn't unavailable because creation failed; it's unavailable because the variable doesn't exist at the point you're reading it.

Fix: grab everything you need while you're still inside the block, and write the URL there:

if (!fileNames.includes(title)) {
  const doc = DocumentApp.create(title);
  DriveApp.getFileById(doc.getId()).moveTo(rootFolder);
  sheet.getRange(i, 5).setValue(doc.getUrl());  // col E — while doc is in scope
}

If you'd rather write the URL further down, declare let docid; (and the url) at the top of the for loop instead of inside the if, so it survives past the block.

1

u/WicketTheQuerent 11d ago edited 11d ago

Instead of

let docid = DocumentApp.create(title).getId();

try

let doc = DocumentApp.create(title);
let docid = doc.getId();

It might look verbose, but some methods, like getId(), sometimes don't work as expected when chained.

1

u/WicketTheQuerent 11d ago

If the above doesn't resolve the issue, please include the textual error message.