Rejected promise is not reaching catch - node.js

I'm trying to use this method for non-sequential promise output.
The express .json call successfully sends a 201 alongside the user object from the API, but in the console, I get the Unhandled rejection error shown below. This seems like it should be caught by the .catch handler in the controller. I am wondering why this could be happening?
userController
module.exports.postUser = function (req, res, next) {
var user = req.body.user;
var ip = req.ip;
userService.createUser(user, ip)
.then(function (user) {
res.status(201).json({"user": user.toJSON()});
})
.catch(function (err) {
return next(err);
});
};
userService
module.exports.createUser = function (user, ip) {
var user = new Promise(function (resolve, reject) {
return resolve(User.forge(user));
});
return user.then(function validateUser(user) {
return user.validate({validatePassword: true});
})
.then(function hash() {
var password = user.value().get('password');
return hashPassword(password);
})
.then(function setPassword(hashedPass) {
user.value().set('hashedPass', hashedPass);
return user.value().save();
})
.then(function () {
return user;
});
};
output
Unhandled rejection error: null value in column "status" violates not-null constraint
at Connection.parseE (/Users/lukel99/webstorm-workspace/rocketwagon-postgres-kickstart/node_modules/pg/lib/connection.js:539:11)
at Connection.parseMessage (/Users/lukel99/webstorm-workspace/rocketwagon-postgres-kickstart/node_modules/pg/lib/connection.js:366:17)
at Socket.<anonymous> (/Users/lukel99/webstorm-workspace/rocketwagon-postgres-kickstart/node_modules/pg/lib/connection.js:105:22)
at Socket.emit (events.js:107:17)
at readableAddChunk (_stream_readable.js:163:16)
at Socket.Readable.push (_stream_readable.js:126:10)
at TCP.onread (net.js:538:20)
From previous event:
at Client._query (/Users/lukel99/webstorm-workspace/rocketwagon-postgres-kickstart/node_modules/knex/lib/dialects/postgres/index.js:122:12)
at Client.query (/Users/lukel99/webstorm-workspace/rocketwagon-postgres-kickstart/node_modules/knex/lib/client.js:127:24)
at Runner.<anonymous> (/Users/lukel99/webstorm-workspace/rocketwagon-postgres-kickstart/node_modules/knex/lib/runner.js:118:24)
From previous event:
at /Users/lukel99/webstorm-workspace/rocketwagon-postgres-kickstart/node_modules/knex/lib/runner.js:44:21
From previous event:
at Runner.run (/Users/lukel99/webstorm-workspace/rocketwagon-postgres-kickstart/node_modules/knex/lib/runner.js:30:20)
at QueryBuilder.Target.then (/Users/lukel99/webstorm-workspace/rocketwagon-postgres-kickstart/node_modules/knex/lib/interface.js:27:43)
at null.<anonymous> (/Users/lukel99/webstorm-workspace/rocketwagon-postgres-kickstart/node_modules/bookshelf/lib/model.js:208:36)
at processImmediate [as _immediateCallback] (timers.js:367:17)

The most likely cause is that return user.value().save() does not return a promise, but implements callbacks instead. If that is the case, then the error would be thrown outside of the native promise try/catch block, and would hence not be caught but your .catch().

Related

creating custom token in cloud function after reteiving data from realtime database

i want to create custom token in cloud function but before that I want to check and compare timestamp from realtime database and with current time.if the timestamp is below 10 min then I want to create custom token and send back to client.please help me to achieve this.i am new to this cloud function firebase.
here is my code
export const authaccount = functions.https.onCall(async (data) => {
try {
const snap= await admin.database().ref("/register/"+data).get();
const time=snap.val().timestamp;
const now=new Date().getDate();
const reg=new Date(time).getDate();
const today=Math.abs(now-reg);
const daydiff=Math.floor(today/1000/60/60/24);
const nowminutes=new Date().getUTCMinutes();
const regminutes=new Date(time).getUTCMinutes();
const timediff=Math.abs(nowminutes-regminutes);
if (timediff<10 && daydiff==0) {
try {
admin.auth().createCustomToken(data).then((customtoken)=>{
console.log("auth created"+" "+timediff+" "+daydiff+" "+customtoken);
return customtoken;
});
} catch (err1) {
throw new functions.https.HttpsError("unknown", err1.message, err1);
}
} else {
console.log("else "+" "+now+" "+reg+" "+time+" "+daydiff);
}
} catch (err2) {
throw new functions.https.HttpsError("unknown", err2.message, err2);
}
});
2:53:20.626 AM
authaccount
Error: Process exited with code 16 at process.<anonymous> (/layers/google.nodejs.functions-framework/functions-framework/node_modules/#google-cloud/functions-framework/build/src/invoker.js:275:22) at process.emit (events.js:314:20) at process.EventEmitter.emit (domain.js:483:12) at process.exit (internal/process/per_thread.js:168:15) at Object.sendCrashResponse (/layers/google.nodejs.functions-framework/functions-framework/node_modules/#google-cloud/functions-framework/build/src/logger.js:37:9) at process.<anonymous> (/layers/google.nodejs.functions-framework/functions-framework/node_modules/#google-cloud/functions-framework/build/src/invoker.js:271:22) at process.emit (events.js:314:20) at process.EventEmitter.emit (domain.js:483:12) at processPromiseRejections (internal/process/promises.js:209:33) at processTicksAndRejections (internal/process/task_queues.js:98:32)
2:53:19.559 AM
authaccount
Error: The caller does not have permission; Please refer to https://firebase.google.com/docs/auth/admin/create-custom-tokens for more details on how to use and troubleshoot this feature. at FirebaseAuthError.FirebaseError [as constructor] (/workspace/node_modules/firebase-admin/lib/utils/error.js:44:28) at FirebaseAuthError.PrefixedFirebaseError [as constructor] (/workspace/node_modules/firebase-admin/lib/utils/error.js:90:28) at new FirebaseAuthError (/workspace/node_modules/firebase-admin/lib/utils/error.js:149:16) at Function.FirebaseAuthError.fromServerError (/workspace/node_modules/firebase-admin/lib/utils/error.js:188:16) at /workspace/node_modules/firebase-admin/lib/auth/token-generator.js:114:53 at processTicksAndRejections (internal/process/task_queues.js:97:5) at async Promise.all (index 1)
2:53:19.558 AM
authaccount
Unhandled rejection
2:53:19.469 AM
authaccount
Function execution took 1386 ms, finished with status code: 200
please help to solve this problem. i don't know where I am making the mistake.
You will need to make sure your Firebase Admin sdk is initiated and running before the function proceeds
if (firebase.apps.length === 0) {
firebase.initializeApp();
}
Resource: https://firebase.google.com/docs/admin/setup#initialize-without-parameters
I doubt you have modified the IAM permissions on your service account but as the comment suggested: https://firebase.google.com/docs/auth/admin/create-custom-tokens#service_account_does_not_have_required_permissions
Once that is confirmed to be working - you will need to ensure that the onCall data is a string and not null, some simple health checks can help you debug your process
console.log(typeof data);
console.warn("Data", data);
from there I would also debug your date times and the realtime database result, these are async and will require the promise to be resolved before you can use it.
Update:
All cloud functions should return a response to the client
onCall uses promises on the client and supports a 'return Object'
example:
return {
token: myCustomToken,
possible: otherValue
};
for comparison, onRequest uses fetch like responses and supports codes
response.status(500)
response.send({name:value})
return;
Source:
https://firebase.google.com/docs/functions/callable#sending_back_the_result
Source:
https://firebase.google.com/docs/functions/http-events#using_express_request_and_response_objects
Update:
all paths and promises need to resolve correctly, this includes awaiting promises to resolve and returning their result or storing the result for any secondary processing - I suggest cleaning up the code, remove the try/catch and use .then().catch()
Example:
if (timediff<10 && daydiff==0) {
return await admin.auth().createCustomToken(data)
.then((customtoken)=>{
console.log("auth created"+" "+timediff+" "+daydiff+" "+customtoken);
return customtoken;
})
.catch (err) {
return new functions.https.HttpsError("unknown", err.message, err);
}
}
else {
console.log("else "+" "+now+" "+reg+" "+time+" "+daydiff);
return "else "+" "+now+" "+reg+" "+time+" "+daydiff;
}

Node Express js Unhandled rejection Error [ERR_HTTP_HEADERS_SENT]

I am new for node js. I am trying to insert the data to database, before that I did some validation for checking username already exist in database. Please see the coding which is used by me.
var express = require("express");
var router = express.Router();
var models = require("../models");
const { check, validationResult } = require('express-validator/check');
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource - merchant');
});
/* POST ADD USERS. */
router.post('/add-merchant', [
check('name').not().isEmpty(),
], (req, res, next) => {
try {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.json({ errors: errors.array()});
}
console.log("error passed")
models.merchants.findOne({ where: {name: req.body.name}}).then((merchant) => {
if(merchant) {
throw new Error("Username already exists")
}
models.merchants.create(req.body).then((merchant) => {
res.json(merchant)
});
})
} catch (error) {
res.json({"status": "error", "message": error.message})
}
});
module.exports = router;
I am getting below error while running the above code
Unhandled rejection Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:470:11)
at ServerResponse.header (/home/assistanz/Desktop/node/gb360/node_modules/express/lib/response.js:767:10)
at ServerResponse.send (/home/assistanz/Desktop/node/gb360/node_modules/express/lib/response.js:170:12)
at ServerResponse.json (/home/assistanz/Desktop/node/gb360/node_modules/express/lib/response.js:267:15)
at models.merchants.create.then (/home/assistanz/Desktop/node/gb360/routes/merchant.js:33:21)
at tryCatcher (/home/assistanz/Desktop/node/gb360/node_modules/bluebird/js/release/util.js:16:23)
at Promise._settlePromiseFromHandler (/home/assistanz/Desktop/node/gb360/node_modules/bluebird/js/release/promise.js:512:31)
at Promise._settlePromise (/home/assistanz/Desktop/node/gb360/node_modules/bluebird/js/release/promise.js:569:18)
at Promise._settlePromise0 (/home/assistanz/Desktop/node/gb360/node_modules/bluebird/js/release/promise.js:614:10)
at Promise._settlePromises (/home/assistanz/Desktop/node/gb360/node_modules/bluebird/js/release/promise.js:694:18)
at _drainQueueStep (/home/assistanz/Desktop/node/gb360/node_modules/bluebird/js/release/async.js:138:12)
at _drainQueue (/home/assistanz/Desktop/node/gb360/node_modules/bluebird/js/release/async.js:131:9)
at Async._drainQueues (/home/assistanz/Desktop/node/gb360/node_modules/bluebird/js/release/async.js:147:5)
at Immediate.Async.drainQueues [as _onImmediate] (/home/assistanz/Desktop/node/gb360/node_modules/bluebird/js/release/async.js:17:14)
at runCallback (timers.js:705:18)
at tryOnImmediate (timers.js:676:5)
at processImmediate (timers.js:658:5)
Please help anyone to solve this issue.
Thanks in advance.
this error occurs because you return the response and something is remain to load
you have to remove console.log("error passed") or you can put it before return statement..
and write return statement for every res.json statement
as
return res.json({})
HTTP uses a cycle that requires one response per request. When the client sends a request the server should send only one response back to client. So modify the code as below,
models.merchants.findOne({ where: { name: req.body.name } }).then((merchant) => {
if (merchant) {
throw new Error("Username already exists")
} else {
models.merchants.create(req.body).then((merchant) => {
res.json(merchant)
});
}
})

If I disable NODE_TLS_REJECT_UNAUTHORIZED, my request is still denied

I am disabling Node from rejecting self signed certificates and making a request.
const { USER, PW } = process.env;
const b64 = new Buffer(`${VP_API_USER}:${VP_API_PW}`).toString("base64");
const Authorization = `Basic ${b64}`;
const doFind = async url => {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0;
const results = await fetch(url, { headers: { Authorization } })
.then(r => (r.ok ? r.json() : Promise.reject(r)))
.catch(err => {
return Promise.reject(err);
});
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 1;
return results;
};
I am still being rejected.
{ FetchError: request to https://<url>:55544/contracts failed, reason: connect ECONNREFUSED <url>:55544
at ClientRequest.<anonymous> (/Users/mjhamm75/Developer/sedd-monorepo/node_modules/node-fetch/index.js:133:11)
at emitOne (events.js:116:13)
at ClientRequest.emit (events.js:211:7)
at TLSSocket.socketErrorListener (_http_client.js:387:9)
at emitOne (events.js:116:13)
at TLSSocket.emit (events.js:211:7)
at emitErrorNT (internal/streams/destroy.js:64:8)
at _combinedTickCallback (internal/process/next_tick.js:138:11)
at process._tickCallback (internal/process/next_tick.js:180:9)
name: 'FetchError',
message: 'request to https://<url>:55544/contracts failed, reason: connect ECONNREFUSED <url>:55544',
type: 'system',
errno: 'ECONNREFUSED',
code: 'ECONNREFUSED' }
What am I doing wrong?
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 1;
line should go inside the callback (your then or catch before the return. because a promise gets resolved in the callback, but your line
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 1;
is written outside of it, even though it appears after the statement, it runs immediately without waiting for the callback. so, your tls is effectively never disabled.
I hope this helps:)
Previous answer looks incorrect - await postpones execution of next line until promise will be resolved.
According to the documentation the NODE_TLS_REJECT_UNAUTHORIZED value should be string '0' to disable TLS validation.
This is how I would approach it, if I had to reset the env var afterwards.
Using .finally() the statement will execute regardless of the outcome of the fetch.
const doFind = async url => {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0;
const results = await fetch(url, { headers: { Authorization } })
.then(r => (r.ok ? r.json() : Promise.reject(r)))
.catch(err => {
return Promise.reject(err);
})
.finally(() => {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 1;
});
return results;
};

net.Stream is not a constructor - Node Postgres

I'm trying to connect a Node.js app with a PostgreSQL server. It seems that no matter what I use, I end up with the same error:
bundle.js:16177 ERROR: TypeError: net.Stream is not a constructor
at new Connection (bundle.js:10133)
at new Client (bundle.js:9704)
at Object.create (bundle.js:11308)
at Pool._createResource (bundle.js:510)
at Pool.dispense [as _dispense] (bundle.js:498)
at Pool.acquire (bundle.js:573)
at Pool.pool.connect (bundle.js:11359)
at PG.connect (bundle.js:10876)
at bundle.js:1642
At first I was declaring a new pg.Client() like the example in the documentation here, but got the above error discovered that might be a bad idea according to this stack overflow post.
I tried using pg.connect():
var pg = require('pg'); //postgresql dependency
var connectionString = "postgres://postgres:thisissuchagoodpassword#PostgreSQL/localhost:5432/Milestone1DB"
console.log("Initiating...");
//var connectionString = "postgres://postgres:thisissuchagoodpassword#PostgreSQL9.6/localhost:5432/Milestone1DB";
//var client = new pg.Client();
//connect to the database
console.log("Attempting to connect to the database");
pg.connect(function (err, client, done)
{
if(err)
{
console.log("Error connecting to the database.");
throw err;
}
client.query("SELECT DISTINCT state FROM business ORDER BY state", function (err, result)
{
if(err)
{
console.log("Query resulted in an error.");
throw err;
}
console.log(result.rows[0]);
client.end(function (err)
{
if(err)
{
console.log("Error disconnecting from the databse.");
throw err;
}
});
});
});
Here is the pg-promise code that I tried:
var pgp = require('pg-promise');
var cn = {
host: 'localhost', // server name or IP address;
port: 5432,
database: 'Milestone1DB',
user: 'postgres',
password: 'thisissuchagoodpassword'
};
var db = pgp(cn); // database instance;
db.any("select distict state from business order by state;")
.then(data => {
console.log("DATA:", data);
})
.catch(error => {
console.log("ERROR:", error);
});
I must be missing something, but I don't know where to look. Thank you to anyone who can help me figure out what this error means.
Make sure you are not crossing a context boundary that is corrupting the net prototype chain and stripping away methods like Stream(). I ran into a similar unhandled Promise exception w Node 7.5 and pg-live-select. However it was intermittent because of the way the net reference was being passed around. I ended up using V8 inspector and putting a 'debugger' statement directly above line 13 in connection.js to catch the corruption.
node_modules/lib/connection.js:13
this.stream = config.stream || new net.Stream();
^
TypeError: net.Stream is not a constructor
at new Connection (node_modules/pg-live-select/node_modules/pg/lib/connection.js:13:34)
at new Client (node_modules/pg-live-select/node_modules/pg/lib/client.js:26:37)
at Object.create (node_modules/pg-live-select/node_modules/pg/lib/pool.js:27:24)
at Pool._createResource (node_modules/generic-pool/lib/generic-pool.js:325:17)
at Pool.dispense [as _dispense] (node_modules/generic-pool/lib/generic-pool.js:313:12)
at Pool.acquire (node_modules/generic-pool/lib/generic-pool.js:388:8)
at Pool.pool.connect (node_modules/pg-live-select/node_modules/pg/lib/pool.js:78:14)
at PG.connect (node_modules/pg-live-select/node_modules/pg/lib/index.js:49:8)
at LivePg._updateQuery (node_modules/pg-live-select/index.js:295:6)
at node_modules/pg-live-select/index.js:160:14
at Array.forEach (native)
at Timeout.performNextUpdate [as _onTimeout] (node_modules/pg-live-select/index.js:159:23)
at ontimeout (timers.js:365:14)
at tryOnTimeout (timers.js:237:5)
at Timer.listOnTimeout (timers.js:207:5)

Uncaught ValidationError; mongoose and mocha

I have an instance method on a mongoose schema, and I cannot catch errors it throws with mocha.
The method does not throw, it calls back with error as param, but mocha test doesn't catch that and I get an uncaught error.
Here's an example module, using mongoose to just do something as a method:
var mongoose = require('mongoose');
var model;
function init(callback) {
mongoose.connect('localhost/test', function() {
var schema = new mongoose.Schema({
a: String
});
schema.methods.act = function(param, cb) {
if (!param) {
console.log('Failing, no param.');
return cb(new Error('Text'));
}
this.a = param;
this.save(cb);
};
model = mongoose.model('schema', schema);
callback();
});
}
function run(cb) {
var instance = new model();
instance.save(function(err) {
if (err) {
throw err;
}
instance.act(null, function(err) {
if (err) {
console.log('An error:', err);
cb(err);
};
});
});
}
module.exports = {
init: init,
run: run
};
Here's a simplified mocha tester:
require('should');
var myModule = require('./testm');
describe('test', function() {
before(function(done) {
// prep stuff
myModule.init(done);
});
it('should catch the error', function(done) {
myModule.run(function(err) {
console.log('Error here:', err);
err.message.should.equal('Text');
done();
});
});
});
Running the test doesn't work as expected:
mocha test
test
Failing, no param.
An error: [Error: Text]
Error here: [Error: Text] Text
1) should catch the error
0 passing (30ms)
1 failing
1) test should catch the error:
Uncaught TypeError: Cannot call method 'equal' of undefined
at /home/zlatko/tmp/test.js:14:26
at /home/zlatko/tmp/testm.js:35:9
at model.schema.methods.act (/home/zlatko/tmp/testm.js:14:16)
at Promise.<anonymous> (/home/zlatko/tmp/testm.js:31:14)
at Promise.<anonymous> (/home/zlatko/tmp/node_modules/mongoose/node_modules/mpromise/lib/promise.js:177:8)
at Promise.emit (events.js:98:17)
at Promise.emit (/home/zlatko/tmp/node_modules/mongoose/node_modules/mpromise/lib/promise.js:84:38)
at Promise.fulfill (/home/zlatko/tmp/node_modules/mongoose/node_modules/mpromise/lib/promise.js:97:20)
at handleSave (/home/zlatko/tmp/node_modules/mongoose/lib/model.js:133:13)
at /home/zlatko/tmp/node_modules/mongoose/lib/utils.js:408:16
at /home/zlatko/tmp/node_modules/mongoose/node_modules/mongodb/lib/mongodb/collection/core.js:128:9
at /home/zlatko/tmp/node_modules/mongoose/node_modules/mongodb/lib/mongodb/db.js:1195:7
at /home/zlatko/tmp/node_modules/mongoose/node_modules/mongodb/lib/mongodb/db.js:1903:9
at Server.Base._callHandler (/home/zlatko/tmp/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/base.js:453:41)
at /home/zlatko/tmp/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/server.js:487:18
at MongoReply.parseBody (/home/zlatko/tmp/node_modules/mongoose/node_modules/mongodb/lib/mongodb/responses/mongo_reply.js:68:5)
at null.<anonymous> (/home/zlatko/tmp/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/server.js:445:20)
at emit (events.js:95:17)
at null.<anonymous> (/home/zlatko/tmp/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection_pool.js:207:13)
at emit (events.js:98:17)
at Socket.<anonymous> (/home/zlatko/tmp/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection.js:440:22)
at Socket.emit (events.js:95:17)
at Socket.<anonymous> (_stream_readable.js:765:14)
at Socket.emit (events.js:92:17)
at emitReadable_ (_stream_readable.js:427:10)
at emitReadable (_stream_readable.js:423:5)
at readableAddChunk (_stream_readable.js:166:9)
at Socket.Readable.push (_stream_readable.js:128:10)
at TCP.onread (net.js:529:21)
What can I be doing wrong?
Update: changed to be more clear.
In my opinion, #Louis answer is the best way to check for an error in asynchronous scenarios: just assert if it exists, their types and so on.
But, if you really want to throw an error when you receive it in your callback, you can do it with chai-as-promised, like:
it('should catch the error', function() {
return Promise.resolve(function () {
myModule.run(function(err) {
if (err) {throw err;}
});
}).should.eventually.throw(Error);
});
In my example, I'm using should.js as the assertion library, but you can use whatever assertion library you want.

Resources