title: Node.js unexpected stack overflow with multiple get requests
body: <p>I have a function that GETs a JSON object from a remote server, or from a local cache on-disk.</p>
  
  <p>In a use-case, i have to call this function several thousand times with varying arguments, but when i do so, i get max stack overflow errors. I must be making a recursive call somewhere, but i can't see where it could be as my process.nextTick function calls seem to be in the right place.</p>
  
  <p>I get none of my log.error readouts in the console, which would be evident if any of the recursive calls to retry the request were made.</p>
  
  <p>The console output shows a repeated occurrence of</p>
  
  <blockquote>
    <p>(node) warning: Recursive process.nextTick detected. This will break in the next version of node. Please use setImmediate for recursive deferral.</p>
  </blockquote>
  
  <p>then...</p>
  
  <blockquote>
    <p>RangeError: Maximum call stack size exceeded</p>
  </blockquote>
  
  <p>Then the program exits.</p>
  
  <p>Can anyone offer any help regarding what i may be doing wrong? I'm completely stumped.</p>
  
  <p>Below is the function that invokes the problematic function "tf2inv.loadInventory()"</p>
  
  <pre><code>function refreshInventories(accounts, force, callback) {    
      //job executes download function, then pushes to inventories object
      var inventories = {};
      var Qinv = async.queue(function (task, invCallback) {
          tf2inv.loadInventory(
              task.force,
              task.steamid,
              function(inv, alias) {
                  inventories[alias] = inv;
                  process.nextTick(invCallback);
              }
          );
      }, 100)
  
      //when all queue jobs have finished, callback with populated inventories object
      Qinv.drain = function (err) {
          log.info('All inventories downloaded');
          callback(inventories);
      }
  
      //adding jobs to the queue
      for (var i = accounts.length - 1; i &gt;= 0; i--) {
          Qinv.push({
              force: force,
              steamid: accounts[i]
          });
      };
  }
  </code></pre>
  
  <p>Shown here is the function that either parses from the cache, or requests from the remote server.</p>
  
  <pre><code>//tf2inv
  var loadInventory = function(force, sid, callback) {
      var invLoc = invFolder+sid
      if(force) { 
          if(fs.existsSync(invLoc)) {
              fs.unlinkSync(invLoc);
          }
      }
  
      if(fs.existsSync(invLoc)) {
          var body = fs.readFileSync(invLoc);
          try {
              var inventory = JSON.parse(body);
          } catch (e) {
              fs.unlinkSync(invLoc);
              log.error("parsing " + sid+"'s inventory");
              loadInventory(true, sid, invFolder, callback);  
              return;
          }
          process.nextTick(function() { callback(inventory, sid) })
          return;
      } else {
          var urlPre = "http://api.steampowered.com/IEconItems_440/GetPlayerItems/v0001/?key=";
          var urlSidPre = "&amp;steamid=";
          var urlInvSuf = "&amp;inventory=yes";
          var URL = urlPre+steam_API+urlSidPre+sid+urlInvSuf;
          http.get(URL, function (res) {
              var body = '';
              res.on('data', function (data) {
                  body+=data; 
                  fs.appendFile(invLoc, data);
              });
              res.on('end', function() {
                  try {
                      inventory = JSON.parse(body);
                  } catch (e) {
                      if(fs.existsSync(invLoc)) {
                          fs.unlinkSync(invLoc);
                      }
                      log.error("parsing " + sid+"'s downloaded inventory");
                      loadInventory(force, sid, invFolder, callback)
                      return;
                  }
                  process.nextTick(function() { callback(inventory, sid) })
                  return;
              });
              res.on('error', function (e, socket) {
                  log.error(sid + " inventory error")
                  if(fs.existsSync(invLoc)) {
                      fs.unlinkSync(invLoc);
                  }
                  log.debug('Retrying inventory') 
                  loadInventory(force, sid, invFolder, callback);
                  return;
              })
              res.on('close', function () {res.emit('end'); log.error('connection closed')})
          })
          .on('error', function(e) {
              log.error(JSON.stringify(e));
              if(fs.existsSync(invLoc)) {
                  fs.unlinkSync(invLoc);
              }
              log.debug('Retrying inventory') 
              loadInventory(force, sid, invFolder, callback)
              return;
          })
      }
  };
  </code></pre>