6

See Update Below

I have written a Node.js application with Express that works fine locally, but when I run the app on Heroku, it gives me the following error:

2013-01-19T21:55:42+00:00 app[web.1]: module.js:340
2013-01-19T21:55:42+00:00 app[web.1]:     throw err;
2013-01-19T21:55:42+00:00 app[web.1]:     ^
2013-01-19T21:55:42+00:00 app[web.1]: Error: Cannot find module './blog/blog'
2013-01-19T21:55:42+00:00 app[web.1]:     at Function.Module._load (module.js:312:12)
2013-01-19T21:55:42+00:00 app[web.1]:     at Module.require (module.js:362:17)
2013-01-19T21:55:42+00:00 app[web.1]:     at Object.Module._extensions..js (module.js:467:10)
2013-01-19T21:55:42+00:00 app[web.1]:     at require (module.js:378:17)
2013-01-19T21:55:42+00:00 app[web.1]:     at Object.<anonymous> (/app/app.js:15:12)
2013-01-19T21:55:42+00:00 app[web.1]:     at Function.Module._resolveFilename (module.js:338:15)
2013-01-19T21:55:42+00:00 app[web.1]:     at Module.load (module.js:356:32)
2013-01-19T21:55:42+00:00 app[web.1]:     at Module.runMain (module.js:492:10)
2013-01-19T21:55:42+00:00 app[web.1]:     at Function.Module._load (module.js:280:25)
2013-01-19T21:55:42+00:00 app[web.1]:     at Module._compile (module.js:449:26)
2013-01-19T21:55:43+00:00 heroku[web.1]: Process exited with status 1
2013-01-19T21:55:43+00:00 heroku[web.1]: State changed from starting to crashed

I don't understand why it doesn't work on Heroku, because the exact same code works perfectly locally. Maybe it has something to do with how I put the code on Heroku's server? Just in case, below is my filesystem, the code for my app.js file, and my blog.js module that I want app.js to load:

filesystem:

filesystem

app.js:

//requires and starts up app
var express = require('express');
var app = express();

//db setup
var mongoose = require('mongoose')
  , dbURI = 'localhost/brads-projects';

//configures app for production, connects to MongoHQ databse rather than localhost
app.configure('production', function () {
  dbURI = process.env.MONGOHQ_URL;
});

//requires the various project files
var blog = require('./blog/blog').blog;

//tries to connect to database.
mongoose.connect(dbURI);
//once connection to database is open, then rest of app runs
mongoose.connection.on('open', function () {
  //runs the blog app
  blog(app, express);

  app.listen(process.env.PORT || 5000);
});

//in the event of a connection to database error, the app will not run
mongoose.connection.on('error', console.error.bind(console, 'connection error:'));

blog.js:

module.exports.blog = function(app, express) {
    //models
    var postmodel = require('./models/post').postmodel
      , usermodel = require('./models/user').usermodel
      , notificationmodel = require('./models/notification').notificationmodel
      , commentmodel = require('./models/comment').commentmodel;

    //controllers
    var indexHandler = require('./controllers/index').index
      , newpostHandler = require('./controllers/newpost').newpost
      , postandidHandler = require('./controllers/postandid').postandid
      , newPostHandler = require('./controllers/newpost').newpost
      , searchHandler = require('./controllers/search').postsearch
      , loginHandler = require('./controllers/login').login
      , logoutHandler = require('./controllers/login').logout
      , dashboardHandler = require('./controllers/dashboard').dashboard
      , registerHandler = require('./controllers/register').register
      , userSettingsHandler = require('./controllers/usersettings').usersettings
      , editpostHandler = require('./controllers/editpost').editpost
      , newCommentHandler = require('./controllers/newcomment').newcomment;

    //misc requires
    var MemStore = require('connect/lib/middleware/session/memory');

    //configures app for general stuff needed such as bodyParser and static file directory
    app.configure(function () {
        app.use(express.bodyParser());
        app.use(express.static(__dirname + '/static'));
        app.use(express.cookieParser('lockirlornie123'));
        app.use(express.session({store: MemStore( {
            reapInterval: 60000 * 10
        })}));
    });

    //requires a user session for access
    function requiresLogin(request, response, next) {
        if (request.session.user) {
            next();
        } else {
            response.redirect('/blog/login');
        }
    };

    //requires user session and admin for access
    function requiresLoginAndAdmin(request, response, next) {
        if (request.session.user && request.session.user.role === 'admin') {
            next();
        } else {
            if (request.session.user) {
                response.redirect('/blog');
            } else {
                response.redirect('/blog/login');
            }
        }
    };

    console.log("loaded");

    var PostModel = new postmodel();
    var Post = PostModel.setupPostSchema();

    var UserModel = new usermodel();
    var User = UserModel.setupUserSchema();

    var NotificationModel = new notificationmodel();
    var Notification = NotificationModel.setupNotificationSchema();
    NotificationModel.clickNotificationHandler(app, Notification);

    var CommentModel = new commentmodel();
    var Comment = CommentModel.setupCommentSchema();

    app.set('views', __dirname + '/views');
    app.set('view engine','jade');

    /*
    var newuser = new User({email: "brad.ross.35@gmail.com", password: UserModel.createHashPass("Brad1234"), role: 'admin', activated: true});
    newuser.save(function (err) {
        if (err) {
            console.log("error saving!");
        } else {
            console.log("successfully created!");
        }
    });
    */

    //get request for the home page that displays the 10 most recent posts
    indexHandler(app, Post, PostModel, NotificationModel.getNotifications, Notification);

    //get request for the unique page for every post
    postandidHandler(app, Post, NotificationModel.getNotifications, Notification, CommentModel.getComments, Comment);

    //post request for the submit url that creates a new post and puts it into the database
    //if a get request is sent to the sumbit page, it redirects users away from the /submit url in order to keep them away and not cause errors.
    newPostHandler(app, Post, requiresLogin, PostModel, NotificationModel.getNotifications, Notification);

    //post request to create a new comment
    newCommentHandler(app, Comment, requiresLogin, CommentModel, NotificationModel.getNotifications, Notification, NotificationModel.createNotification, Post);

    //get request for search page that both displays search results and allows users to create new search queries
    searchHandler(app, Post, NotificationModel.getNotifications, Notification);

    //login page get request and post request
    loginHandler(app, UserModel.authenticate, User);

    //logout page that redirects back to home
    logoutHandler(app);

    //dashboard page for managing posts by user
    //and if user is an admin, adding and deleting users
    dashboardHandler(app, User, Post, requiresLoginAndAdmin, NotificationModel.getNotifications, Notification, Comment);

    //a page for users to register for posting priveleges
    registerHandler(app, User, UserModel, NotificationModel.createNotification, Notification);

    //a page for user settings
    userSettingsHandler(app, User, UserModel, requiresLogin);

    //a page to edit posts
    editpostHandler(app, Post, requiresLogin, NotificationModel.getNotifications, Notification);
};

UPDATE:

Thanks to the suggestions below, I have run heroku run bash to find out what files are actually there, and when I do the following, I find out some intriguing information, namely that the file I am trying to import isn't actually there:

~ $ cd ./blog
~/blog $ ls
~/blog $ cd ..
~ $ cd ./addressbook
~/addressbook $ ls
~/addressbook $ cd ..
~ $ cd ./views
~/views $ ls
addressbook  blog  index
~/views $ cd ./blog
~/views/blog $ ls
dashboard.jade  index.jade    layout.jade  newpost.jade    register.jade
editpost.jade   index_error.jade  login.jade   postandid.jade  search.jade

Looks like something I am doing is not uploading those files in app/blog and app/addressbook. Interesting and a good piece of info. Thanks for the suggestions...

Brad Ross
  • 451
  • 8
  • 26
  • It seems to me the app is running in a different working directory than you expect on Heroku. What is the value of `process.cwd()`? – myanimal Jan 22 '13 at 08:12
  • @myanimal But so long as `app.js` and `blog.js` are in same directory, it should work fine. – Juzer Ali Jan 22 '13 at 16:29

2 Answers2

5

Based on the information you have provided this might be the answer. In the mac terminal (i'm assuming from the screenshot you are running OSX) run this command from the folder in which the blog.js file is located.

file blog.js -I

This should tell you that the file has a mime type of 'text/plain', if it comes back with a mime type of 'text/x-c' then it looks like the file was originally created on Linux - this is your problem.

To solve this issue simply:

  • create a new file
  • copy the content of blog.js over
  • git rm the old file
  • rename the new file
  • get add the new file

The new file should now have the mime type of 'text/plain'. Push the changes to Heroku and test.

If this was not the issue my next step would be to run:

heroku run bash

And see if the file exists in the location your app is expecting to find it on Heroku. If you still have issue post back the results of these investigations.

Let me know!

Reference: Mac developer Library: 'file' command

webjames
  • 1,087
  • 8
  • 12
  • 1
    You were right! It was a `text/x-c`. `git rm blog.js` returns `pathspec 'blog/blog.js' did not match any files`. Can I just move it to the trash? – Brad Ross Jan 23 '13 at 14:30
  • you might need to run `git rm blog/blog.js` but yes you could remove it to the trash. the important thing is to ensure that your includes are mime type `text/plain`. Create a new file, and copy the contents of the old one into it, and then using the `file blog.js -I` command ensure that the new file is type `text/plain` then add and commit then push to Heroku. – webjames Jan 23 '13 at 21:12
  • Can't figure out how to create a file that is not text/plain. Whenever I create a new file, it always creates it as text/x-c. Maybe it is the .js extension? – Brad Ross Jan 24 '13 at 05:21
  • Hi Brad, this is truly strange but if you remove the following commented out block (lines 75:84) you will notice that the file is now reported as 'text/plain'. Why this is the case is another question! – webjames Jan 24 '13 at 21:06
  • doesn't do that for me. Any other ideas? – Brad Ross Jan 25 '13 at 04:43
  • [This is the file](https://dl.dropbox.com/u/6580544/blog.js) i have tested on my Mac, it is reported as: `blog.js: text/plain; charset=us-ascii` – webjames Jan 25 '13 at 18:16
  • Ok. I have more information posted on the update of the post. Sorry this hasn't been resolved until now! It is kind of crazy, and I am surprised the problem is this complicated. – Brad Ross Jan 26 '13 at 01:23
  • This answer saved me a 2 hour debug. I copied some files over from an old project and heroku reported all copied as not found while it works well in my local. – Ogbonna Vitalis May 07 '20 at 01:20
  • This answer saved me a 2 hour debug. I copied some files over from an old project and heroku reported all copied as not found while it works well in my local. – Ogbonna Vitalis May 07 '20 at 01:20
1

Strange behaviour; Try debugging using:

console.log( __dirname );

Make sure that the following path is correct (points to your blog.js file):

console.log( __dirname + '/blog/blog.js' );

Then try to explicitly pass it to require: (might vary depending on what __dirname returns..)

var blog = require( __dirname + '/blog/blog' ).blog;
Pierre
  • 18,643
  • 4
  • 41
  • 62
  • Here are the logs: `Slug compilation finished 2013-01-26T01:13:01+00:00 heroku[web.1]: Starting process with command `node app.js` 2013-01-26T01:13:05+00:00 app[web.1]: 2013-01-26T01:13:05+00:00 app[web.1]: dirname + /blog/blog.js: /app/blog/blog.js 2013-01-26T01:13:05+00:00 app[web.1]: Error: Cannot find module '/app/blog/blog' 2013-01-26T01:13:05+00:00 app[web.1]: module.js:340 2013-01-26T01:13:05+00:00 app[web.1]: dirname: /app` Still doesn't work, and it seems ok. – Brad Ross Jan 26 '13 at 01:15
  • Ok. I have more information posted on the update of the post. Sorry this hasn't been resolved until now! It is kind of crazy, and I am surprised the problem is this complicated. Tried this out and I think it tells me more info. – Brad Ross Jan 26 '13 at 01:18