title: express js cannot GET /page
body: <p>I am very stuck with a routing error on express.js. I am using jade to render my page views. I have read all the docs and refactored many times to no avail.</p>
  
  <p>This is the plain contents of the link that is pointing to the '/sell' route.</p>
  
  <p><strong>index.jade</strong></p>
  
  <pre><code>include layout
  html
    button.btn.btn-primary(type='submit', href='/sell') Add Item
  </code></pre>
  
  <p>When clicking this button the browser returns the following as a 404: </p>
  
  <blockquote>
    <p>Cannot GET /sell</p>
  </blockquote>
  
  <p>The problem here is that all other routes work correctly, if you are to modify the above href to other pages i.e. '/' , '/sign_in', etc no error occurs. The problem appears to be isolated to the '/sell' route.</p>
  
  <p>The controller with the '/sell' route is below:</p>
  
  <p><strong>server.js</strong></p>
  
  <pre><code>var dotenv = require('dotenv');
  dotenv.load();
  var session = require('express-session')
  var nodemailer = require('nodemailer');
  var passport = require('passport');
  var LocalStrategy = require('passport-local').Strategy;
  var bcrypt = require('bcrypt');
  var async = require('async');
  var crypto = require('crypto');
  var cookieParser = require('cookie-parser');
  var flash = require('express-flash');
  var express = require('express');
  var app = express();
  var mongoose = require('mongoose');
  var root  = __dirname;
  var path = require('path');
  var User = require('./models/user');
  var bodyParser = require('body-parser');
  var errorHelper = require('mongoose-error-helper').errorHelper;
  var validator = require('validator');
  var Item = require("./models/item")
  
  var username, email, password, owner, product_name, condition, details, price;
  
  mongoose.connect(process.env.MONGODB_CONGO_DEV);
  
  // Middleware
  app.set('views', 'app/views');
  app.set('view engine', 'jade');
  app.set('port', process.env.PORT || 3000);
  app.use(logger('dev'));
  app.use(bodyParser.json());
  app.use(bodyParser.urlencoded({ extended: true}));
  app.use(cookieParser());
  app.use(session( {
    secret: 'session secret key',
    resave: false,
    saveUninitialized: true
  }));
  app.use(flash());
  app.use(passport.initialize());
  app.use(passport.session());
  
  // Routing
  
  app.get('/', function(req,res) {
      res.render('index', {
      title: 'Congo',
      message: 'Congo',
      user: req.user
    });
  });
  
  app.get('/sell', function(req,res) {
      res.render('item', {
      title: 'Congo - Sell',
      message: 'Sell',
      user: req.user
    });
  });
  
  app.get('/sign_in', function(req,res) {
      res.render('sign_in', {
      title: 'Congo',
      message: 'sign in motherfucker',
      user: req.user
    });
  });
  
  app.post('/sign_in', function(req, res, next) {
    passport.authenticate('local', function(err, user, info) {
      if (err) return next(err)
      if (!user) {
        req.flash('error', 'Incorrect login details');
        return res.redirect('/sign_in')
      };
      req.logIn(user, function(err) {
        if (err) return next(err);
        res.
        return res.redirect('/');
      });
    })(req, res, next);
  });
  
  app.get('/sign_up', function(req, res) {
    res.render('sign_up', {
      title: 'Congo',
      message: 'sign up',
      user: req.user
    });
  });
  
  app.post('/sign_up', function(req, res) {
    var user = new User({
        username: req.body.username,
        email: req.body.email,
        password: req.body.password
      });
    if (req.body.confirm != req.body.password) {
      req.flash('error', 'Password do not match')
      res.redirect('/sign_up')
    };
    else if (validator.isEmail(req.body.email) === false) {
      req.flash('error', 'Invalid email address')
      res.redirect('/sign_up')
    };
    else {
    user.save(function(err) {
      if (err) {
      req.flash('error', 'Email already in use')
      res.redirect('/sign_up')
      } else {
          req.logIn(user, function(err) {
          res.redirect('/');
        });
        }
      });
    };
  });
  
  app.get('/logout', function(req, res){
    req.logout();
    res.redirect('/');
  });
  
  app.get('/forgot', function(req, res) {
    res.render('forgot', {
      user: req.user,
      message: 'you wally'
    });
  });
  
  app.get('/profile', function(req, res) {
    res.render('profile', {
      user: req.user,
      message: 'User profile'
    });
  });
  
  app.post('/forgot', function(req, res, next) {
    async.waterfall([
      function(done) {
        crypto.randomBytes(20, function(err, buf) {
          var token = buf.toString('hex');
          done(err, token);
        });
      },
      function(token, done) {
        User.findOne({ email: req.body.email }, function(err, user) {
          if (!user) {
            req.flash('error', 'No account with that email address exists.');
            return res.redirect('/forgot');
          };
  
          user.resetPasswordToken = token;
          user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
  
          user.save(function(err) {
            done(err, token, user);
          });
        });
      },
      function(token, user, done) {
        var smtpTransport = nodemailer.createTransport('SMTP', {
          service: 'Gmail',
          auth: {
            user: 'harryandrew.dix@gmail.com',
            pass: process.env.GMAIL_PASS
          };
        });
        var mailOptions = {
          to: user.email,
          from: 'passwordreset@demo.com',
          subject: 'Node.js Password Reset',
          text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' +
            'Please click on the following link, or paste this into your browser to complete the process:\n\n' +
            'http://' + req.headers.host + '/reset/' + token + '\n\n' +
            'If you did not request this, please ignore this email and your password will remain unchanged.\n'
        };
        smtpTransport.sendMail(mailOptions, function(err) {
          req.flash('info', 'An e-mail has been sent to ' + user.email + ' with further instructions.');
          done(err, 'done');
        });
      };
    ], function(err) {
      if (err) return next(err);
      res.redirect('/forgot');
    });
  });
  
  app.get('/reset/:token', function(req,res) {
    User.findOne({resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now()}}, function(err,user) {
      if (!user) {
        req.flash('error', 'Password reset token invalid or expired.');
        return res.redirect('/forgot');
      }
      res.render('reset', {
        user: req.user,
        message: 'reset dem pass'
      });
    });
  });
  
  app.post('/reset/:token', function(req, res) {
    async.waterfall([
      function(done) {
        User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user) {
          if (!user) {
            req.flash('error', 'Password reset token is invalid or has expired.');
            return res.redirect('back');
          };
  
          user.password = req.body.password;
          user.resetPasswordToken = undefined;
          user.resetPasswordExpires = undefined;
  
          user.save(function(err) {
            req.logIn(user, function(err) {
              done(err, user);
            });
          });
        });
      },
      function(user, done) {
        var smtpTransport = nodemailer.createTransport('SMTP', {
          service: 'Gmail',
          auth: {
            user: 'harryandrew.dix@gmail.com',
            pass: process.env.GMAIL_PASS
          };
        });
        var mailOptions = {
          to: user.email,
          from: 'passwordreset@demo.com',
          subject: 'Your password has been changed',
          text: 'Hello,\n\n' +
            'This is a confirmation that the password for your account ' + user.email + ' has just been changed.\n'
        };
        smtpTransport.sendMail(mailOptions, function(err) {
          req.flash('success', 'Success! Your password has been changed.');
          done(err);
        });
      };
    ], function(err) {
      res.redirect('/');
    });
  });
  
  // app.post('/add_item', function(req, res) {
  //   var item = new Item({
  //       owner: req.user.id,
  //       product_name: req.body.product_name,
  //       condition: req.body.condition,
  //       details: req.body.details,
  //       price: req.body.price
  //   });
  //   item.save(function(err) {
  //     if (err) {
  //       req.flash('error', 'Something went wrong, make sure you are signed in.')
  //         res.redirect('/add_item');
  //     } else {
  //       req.logIn(item, function(err) {
  //         res.redirect('/user_profile');
  //       });
  //     };
  //   });
  // });
  
  var server = app.listen(3000, function() {
    var host = server.address().address;
    var port = server.address().port;
  
    console.log('Example app listening at http://%s:%s',host,port);
  });
  </code></pre>
  
  <p><strong>item.jade</strong></p>
  
  <pre><code>include layout
  html
    block content
      form(method='POST')
          legend(style='font-family: Raleway; font-size: 30px;') Item Details
        .form-group
          label(for='product_name') Product Name
          input.form-control(type='text', name='product_name', placeholder='include product name, brand, condition, colour etc.', required autofocus)
        .form-group
          label(for='condition') Condition
          input.form-control(type='text', name='condition', placeholder='e.g. New, Used', required)
        .form-group
          label(for='image') Image
          input.form-control(type='file', name='image')
        .form-group
          label(for='details') Details
          textarea.form-control(name='details', cols='40', rows='5')
        .form-group
          label(for='price') Price
        .input-group
          .input-group-addon £
          input.form-control(type='text', placeholder='Amount', required)
          .input-group-addon .00
        br
        br
        button#btnSubmit.btn.btn-primary(type='submit') Post Item
  </code></pre>