Node.js "Cannot read property 'length' of undefined

I have this node.js app (using socket.io) that is going to be used for monitoring changes made to network configuration changes in a production environment. It monitors a spool directory for new files then pushes the info to a web client. When I try to run it I get "ERROR: Cannot read property 'length' of undefined." Any help would be appreciated.

#!/usr/bin/env node

// Runtime configuration
const SPOOLDIR = process.env['HOME'] + "/spool";        // Where to collect files
const INTERVAL = 5000;                          // How often to scan
const GRACE = 2000;                             // Minimum age of file before processing

// Dependency modules
const fs = require("fs");
const os = require("os");
const util = require("util");
const app = require('http').createServer(handler)
const io = require('socket.io')(app);

// Global variables:
// - File cache: stat structures by filename
var CACHE={};

// Mini C STDIO  printf/fprintf routines :)
//
const STDOUT=1;
const STDERR=2;
const fprintf = function(fd, fmt) {
    utilfmt_args = Array.prototype.slice.call(arguments, 1);
    var str = util.format.apply(null, utilfmt_args);
    fs.writeSync(fd, str);
}
const printf = function() {
    Array.prototype.unshift.call(arguments, STDOUT);
    fprintf.apply(null, arguments);
}


const startFileScan = function() {
    fs.readdir(SPOOLDIR, processFileResults);
}

const processFileResults = function(err, files) {
    fprintf(STDERR, "processFileResult: %d file(s) found in %s\n", files.length, SPOOLDIR);
    if (err!=undefined) {
        fprintf(STDERR, "Can't read spool directory %s: %s\n", SPOOLDIR, err.code);
        return;
    }

    // Expire any items from the cache that are no longer present
    for (var f in CACHE) {
        if (files.indexOf(f)==-1) {
//          fprintf(STDERR, "Removing file %s from cache\n", f);
            delete CACHE[f];
        }
    }

    // Check any files that are there for modifications, processing them if so
    var currentFile = undefined;
        const doStat = function(err, stats) {
        if (err) {
            fprintf(STDERR, "Error stat()ing %s: %s\n", currentFile, err.code);
        } else {
            if (currentFile!==undefined) {
//              fprintf(STDERR, "Checking file %s with mtime %s against cache\n", currentFile, stats.mtime);
                if (!(currentFile in CACHE) || !(CACHE[currentFile].getTime()==stats.mtime.getTime())) {
                    if (stats.mtime.getTime() + GRACE < Date.now()) {
//                      fprintf(STDERR, "  Updating cache for file %s with mtime %s\n", currentFile, stats.mtime);
                        CACHE[currentFile]=stats.mtime;
//                      fprintf(STDERR, "  File %s has been modified longer than %d ms ago: scheduling for processing\n", currentFile, GRACE);
                        process.nextTick(outputDiffReport, currentFile, CACHE[currentFile]);
                }
            }           
        }
        currentFile = files.pop();
        if (currentFile===undefined) {
//          fprintf(STDERR, "File scan completed: re-scheduling next scan\n");
            process.nextTick(function() { setTimeout(startFileScan, INTERVAL); });
        } else {
            fs.stat(SPOOLDIR + "/" + currentFile, doStat);                      
        }
    };
    process.nextTick(doStat);
}

// App library routines
//
    const outputDiffReport = function(filename, mtime) {
//  fprintf(STDERR, "Processing file %s\n", filename);
    var data="";
    try {
        data = fs.readFileSync(SPOOLDIR + "/" + filename, { encoding: "utf8" });
    } catch(err) {
        fprintf(STDERR, "Can't read incoming filename %s: %s\n", filename, err.code);
    }
    content = data.split(/\n/).filter(function(x) { return x.match(/^[+\-#\[]/); }).join("\n"); 
//  content = data.split(/\n/).filter(function(x) { return ! x.match(/^\s*$/); }).join("\n");   

    io.emit('update', { 'content':  content,
                        'mtime':    mtime.toISOString(),
                        'file':     filename
                    });

fs.unlink(SPOOLDIR + "/" + filename, function() {});
}


// HTTP bootstrap handler routine. Serves out the client HTML
function handler (req, res) {
  fs.readFile(__dirname + '/index.html',
  function (err, data) {
    if (err) {
      res.writeHead(500);
      return res.end('Error loading index.html');
    }
    res.writeHead(200);
    res.end(data);
  });
}

process.on('uncaughtException', function(err) {
  console.log("ERROR: ", err.message);
  process.exit(1);
});

app.listen(8080);

process.nextTick(startFileScan);

1 answer

  • answered 2018-10-19 21:04 hlfrmn

    When processFileResults is called, it will either get an error as first param, or it will succeed and give you null as first param and the files as the second.

    Before you try to access the files, you should check for the error and handle it. Also, it doesn't make sense semantically to check if error is undefined, since it can only be null or an error.

    const processFileResults = function(err, files) {
        if (err) {
            fprintf(STDERR, "Can't read spool directory %s: %s\n", SPOOLDIR, err.code);
            return;
        }
        fprintf(STDERR, "processFileResult: %d file(s) found in %s\n", files.length, SPOOLDIR);
    }