ReferenceError: Cannot access 'fs' before initialization - node.js

I try to use fs on a discordjs bot (v13) but I have a strange error.
I have literally 3 lines between the moment when I can console.log my fs object and the error :
// Get FS
const fs = require('fs');
// Recieves commands
client.on('interactionCreate', async interaction => {
console.log(fs); // OK
switch(interaction.commandName) {
// Get list of all maps for this server
case 'maps':
const pngfiles = fs.readdirSync('./maps/').filter(f => f.endsWith(".png")); // NOT OK !!!!!!!
response = "**List all maps available in this server:**\n\n\n"+pngfiles.join("\n")+"\n";
break;
}
});
And the error :
/home/chenille33/DPW/app.js:156
const pngfiles = fs.readdirSync('./maps/').filter(f => f.endsWith(".png"));
^
ReferenceError: Cannot access 'fs' before initialization
at Client.<anonymous> (/home/chenille33/DPW/app.js:156:34)
at Client.emit (node:events:527:28)
at InteractionCreateAction.handle (/home/chenille33/DPW/node_modules/discord.js/src/client/actions/InteractionCreate.js:74:12)
at module.exports [as INTERACTION_CREATE] (/home/chenille33/DPW/node_modules/discord.js/src/client/websocket/handlers/INTERACTION_CREATE.js:4:36)
at WebSocketManager.handlePacket (/home/chenille33/DPW/node_modules/discord.js/src/client/websocket/WebSocketManager.js:351:31)
at WebSocketShard.onPacket (/home/chenille33/DPW/node_modules/discord.js/src/client/websocket/WebSocketShard.js:444:22)
at WebSocketShard.onMessage (/home/chenille33/DPW/node_modules/discord.js/src/client/websocket/WebSocketShard.js:301:10)
at WebSocket.onMessage (/home/chenille33/DPW/node_modules/ws/lib/event-target.js:199:18)
at WebSocket.emit (node:events:527:28)
at Receiver.receiverOnMessage (/home/chenille33/DPW/node_modules/ws/lib/websocket.js:1137:20)
Node.js v18.0.0
What I've missed ? Thanks in advance.

That specific error implies that somewhere else in your function scope (not shown in the code in your question), you likely have const fs = ... or let fs = ... and are thus attempting to redefine fs in this function scope which is hiding the higher scoped fs.
The error means that you're trying to use the variable fs BEFORE its const fs = ... or let fs = ... definition in this scope have been executed. Unlike with var (where definitions are internally hoisted), you can't use a variable before its declaration with let or const.
Based on the bit of code we can see, I would guess you're doing this in one of the other case handlers in your switch statement or somewhere else in the function containing this switch statement. When you don't use braces to define a new scope for each case handler, then those are ALL within the same scope and all const or let definitions there can interfere with each other.
So, look for a redefinition of fs somewhere else in this function. And, if that isn't obvious to you, then post all the code for this function where the error occurs.
Here's a stand-alone example that reproduces that exact same error. This is the kind of thing you should be looking for:
let greeting = "hi";
const fs = require('fs');
switch (greeting) {
case "hi":
fs.readFileSync("temp.js");
console.log("got hi");
break;
case "goodbye":
const fs = require('fs'); // this redefinition causes the error
// when the "hi" case executes
console.log("got goodbye");
break;
default:
console.log("didn't match");
break;
}
// or a redefinition of fs here (in the same function) would also cause the error
When you run this, it gives this error:
ReferenceError: Cannot access 'fs' before initialization
Or, similarly, if you were defining fs somewhere else in the same function containing the switch statement, but after the switch statement. That would also cause the same problem.

Related

Why am I getting a NOENT using Node core module 'fs'

This a repeat question (not yet answered) but I have revised and tightened up the code. And, I have included the specific example. I am sorry to keep beating this drum, but I need help.
This is a Node API. I need to read and write JSON data. I am using the Node core module 'fs', not the npm package by the same name (or fs-extra). I have extracted the particular area of concern onto a standalone module that is shown here:
'use strict';
/*==================================================
This service GETs the list of ids to the json data files
to be processed, from a json file with the id 'ids.json'.
It returns and exports idsList (an array holding the ids of the json data files)
It also calls putIdsCleared to clear the 'ids.json' file for the next batch of processing
==================================================*/
// node modules
const fs = require('fs');
const config = require('config');
const scheme = config.get('json.scheme')
const jsonPath = config.get('json.path');
const url = `${scheme}${jsonPath}/`;
const idsID = 'ids.json';
const uri = `${url}${idsID}`;
let idsList = [];
const getList = async (uri) => {
await fs.readFile(uri, 'utf8', (err, data) => {
if (err) {
return(console.log( new Error(err.message) ));
}
return jsonData = JSON.parse(data);
})
}
// The idea is to get the empty array written back to 'ids.json' before returning to 'process.js'
const clearList = async (uri) => {
let data = JSON.stringify({'ids': []});
await fs.writeFile(uri, data, (err) => {
if (err) {
return (console.log( new Error(err.message) ));
}
return;
})
}
getList(uri);
clearList(uri)
console.log('end of idsList',idsList);
module.exports = idsList;
Here is the console output from the execution of the module:
Error: ENOENT: no such file or directory, open 'File:///Users/doug5solas/sandbox/libertyMutual/server/api/ids.json'
at ReadFileContext.fs.readFile [as callback]
(/Users/doug5solas/sandbox/libertyMutual/server/.playground/ids.js:24:33)
at FSReqWrap.readFileAfterOpen [as oncomplete] (fs.js:235:13)
Error: ENOENT: no such file or directory, open 'File:///Users/doug5solas/sandbox/libertyMutual/server/api/ids.json'
at fs.writeFile
(/Users/doug5solas/sandbox/libertyMutual/server/.playground/ids.js:36:34)
at fs.js:1167:7
at FSReqWrap.oncomplete (fs.js:141:20)
I am being told there is no such file or directory. However I can copy the uri (as shown in the error message)
File:///Users/doug5solas/sandbox/libertyMutual/server/api/ids.json
into the search bar of my browser and this is what is returned to me:
{
"ids": [
"5sM5YLnnNMN_1540338527220.json",
"5sM5YLnnNMN_1540389571029.json",
"6tN6ZMooONO_1540389269289.json"
]
}
This result is the expected result. I do not "get" why I can get the data manually but I cannot get it programmatically, using the same uri. What am I missing? Help appreciated.
Your File URI is in the wrong format.
It shouldn't contain the File:// protocol (that's a browser-specific thing).
I'd imagine you want C://Users/doug5solas/sandbox/libertyMutual/server/api/ids.json.
I solved the problem by going to readFileSync. I don't like it but it works and it is only one read.

bluebird npm TypeError: Cannot read property 'call' of null

I am using bluebird npm,I am getting the above error
I am calling three different function & doing some database operation, but I am getting this error.
If I tried with two functions, it is working but with three function it is throwing error, TypeError: Cannot read property 'call' of null.
If you go to bluebird/js/release/using.js and comment the line no 39 ;
If I comment this line, then this issue is not coming & all is working fine.
If you want more info please Click Here
This is main.js
var myModule = require('../lib/myModule');
var sync = require('deasync');
var id = 90;
var moduleObj = new moduleEntity(id);
console.log(moduleObj);
var id = 90;
var moduleObj = new moduleEntity(id);
console.log(moduleObj);
var id = 90;
var moduleObj = new moduleEntity(id);
console.log(moduleObj);
In MyModule.js
var deasync = require('deasync');
var dbEntity = require('../db/dbEntity');
module.exports = function (id) {
var outputEntity;
dbEntity(id, function(data){
outputEntity = data
});
while(outputEntity === undefined) { deasync.runLoopOnce();};
return outputEntity;
};
In dbEntery.js
var Promise = require("bluebird");
var getConnection = require('./dbcon');
module.exports = function (id,cb) {
var sql_getRecords = SELECT * from tanle_name;
Promise.using(getConnection, function (conn) {
return conn.query(sql_getRecords).then(function(data){
cb(data[0]);
})
});
};
Here is error stack trace
TypeError: Cannot read property 'call' of null
at FunctionDisposer.doDispose (/home/user/Projects/project_name/node_modules/bluebird/js/release/using.js:98:18)
at FunctionDisposer.Disposer.tryDispose (/home/user/Projects/project_name/node_modules/bluebird/js/release/using.js:78:20)
at iterator (/home/user/Projects/project_name/node_modules/bluebird/js/release/using.js:36:53)
at dispose (/home/user/Projects/project_name/node_modules/bluebird/js/release/using.js:48:9)
at /home/user/Projects/project_name/node_modules/bluebird/js/release/using.js:194:20
at PassThroughHandlerContext.finallyHandler (/home/user/Projects/project_name/node_modules/bluebird/js/release/finally.js:55:23)
at PassThroughHandlerContext.tryCatcher (/home/user/Projects/project_name/node_modules/bluebird/js/release/util.js:16:23)
at Promise._settlePromiseFromHandler (/home/user/Projects/project_name/node_modules/bluebird/js/release/promise.js:510:31)
at Promise._settlePromise (/home/user/Projects/project_name/node_modules/bluebird/js/release/promise.js:567:18)
at Promise._settlePromise0 (/home/user/Projects/project_name/node_modules/bluebird/js/release/promise.js:612:10)
at Promise._settlePromises (/home/user/Projects/project_name/node_modules/bluebird/js/release/promise.js:687:18)
at Async._drainQueue (/home/user/Projects/project_name/node_modules/bluebird/js/release/async.js:133:16)
at Async._drainQueues (/home/user/Projects/project_name/node_modules/bluebird/js/release/async.js:143:10)
at Immediate.Async.drainQueues (/home/user/Projects/project_name/node_modules/bluebird/js/release/async.js:17:14)
at runCallback (timers.js:651:20)
at tryOnImmediate (timers.js:624:5)
Bluebird version -- 3.5
Node Version -- v7.6.0
You provided no code examples so it's hard to give you any detailed answer but here are some things that you have to keep in mind when you get error like this.
TypeError: Cannot read property 'call' of null means that some code (also impossible to tell you which code because you didn't provide an example and full error stack trace) tries to bind some function to some this object and arguments using Function.prototype.call() - see:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call
but instead of the function it got null.
Now you need to follow the stack trace and see which code is trying to call the function and where the null originated to fix your problem.
Note that it is null and not undefined so it must have been provided explicitly instead of just being a missing argument to a function call or a missing property on an object. This is an important hint that should let you diagnose the problem much easier.

Stub require in node js

Is it any way to stub require in node js using sinon.js?
For example, i have some file:
const myModule = require('awesomeModule');
And I want to have such stub in my tests:
myRequireStub.withArgs('awesomModule').throws(new Error('some error'));
This works:
const sinon = require('sinon');
let myRequireStub = sinon.stub(module, 'require');
myRequireStub.withArgs('awesomeModule').throws(new Error('some error'));
const myModule = require('awesomeModule');
// Error: some error
However, by stubbing require you'll pretty much break the ability to load modules, so I'm not sure how useful this is.
Depending on your usage, it's probably best to use a library such as mockery or mock-require. But I needed a way to stub all calls to require, so this is what I came up with:
const _module = require('module');
let require = sinon.stub(_module, '_load');
//return a function that returns a function
require.returns(() => { return () => {}; });
//run code that calls require
require.restore();
assert(require.calledWith('module-name'));

Bluebird warning "A promise was created in a handler but was not returned from it"

I get the warning about not returning a created promise from Bluebird and I do not understand why and how I should rewrite my code.
(I have tried reading about the warning at Bluebird API page and the anti-pattern page as I suspect this is what I'm doing)
In my view.js file:
var express = require('express'),
router = express.Router(),
settings = myReq('config/settings'),
Sets = myReq('lib/Sets'),
log = myReq('lib/utils').getLogger('View');
router.get('/:setId/', function(req, res, next) {
var
setId = req.params.setId,
user = req.user,
set = new Sets(setId, user);
log.info('Got a request for set: ' + setId);
// The below line gives the warning mentioned
set.getSet().then(function(output) {
res.send(output);
}).error(function(e){
log.error(e.message, e.data);
res.send('An error occurred while handling set:' + e.message);
});
});
module.exports = router;
In my Sets.js file I have:
var
Promise = require('bluebird'),
OE = Promise.OperationalError,
settings = myReq('config/settings'),
UserData = myReq('lib/userData'),
log = myReq('lib/utils').getLogger('sets'),
errorToSend = false;
module.exports = function(setId, user) {
var
sets = myReq('lib/utils').getDb('sets');
return {
getSet : function() {
log.debug('Getting set')
return sets.findOneAsync({
setId:setId
}).then(function(set){
if ( set ) {
log.debug('got set from DB');
} else {
set = getStaticSet(setId);
if ( ! set ) {
throw new OE('Failed getting db records or static template for set: ' + setId );
}
log.debug('got static set');
}
log.debug('I am handling set')
if ( ! checkSet(set) ) {
var e = new OE('Failed checking set');
e.data = set;
throw e;
}
return {
view : getView(set),
logic : set.logic,
canEdit : true,
error : errorToSend
};
});
}
};
};
So the line in my view.js file with "set.getSet()" gives the warning about not returning the created promise. It seems like this script still does what I expect it to do, but I do not understand why I get the warning.
Stacktrace:
Warning: a promise was created in a handler but was not returned from it
at Object.getSet (C:\dev\infoscrn\lib\Sets.js:36:25)
at C:\dev\infoscrn\routes\view.js:39:20
at Layer.handle [as handle_request] (C:\dev\infoscrn\node_modules\express\lib\router\layer.js:82:5)
at next (C:\dev\infoscrn\node_modules\express\lib\router\route.js:110:13)
at Route.dispatch (C:\dev\infoscrn\node_modules\express\lib\router\route.js:91:3)
at Layer.handle [as handle_request] (C:\dev\infoscrn\node_modules\express\lib\router\layer.js:82:5)
at C:\dev\infoscrn\node_modules\express\lib\router\index.js:267:22
at param (C:\dev\infoscrn\node_modules\express\lib\router\index.js:340:14)
at param (C:\dev\infoscrn\node_modules\express\lib\router\index.js:356:14)
at Function.proto.process_params (C:\dev\infoscrn\node_modules\express\lib\router\index.js:400:3)
at next (C:\dev\infoscrn\node_modules\express\lib\router\index.js:261:10)
at Function.proto.handle (C:\dev\infoscrn\node_modules\express\lib\router\index.js:166:3)
at router (C:\dev\infoscrn\node_modules\express\lib\router\index.js:35:12)
at Layer.handle [as handle_request] (C:\dev\infoscrn\node_modules\express\lib\router\layer.js:82:5)
at trim_prefix (C:\dev\infoscrn\node_modules\express\lib\router\index.js:302:13)
at C:\dev\infoscrn\node_modules\express\lib\router\index.js:270:7
at Function.proto.process_params (C:\dev\infoscrn\node_modules\express\lib\router\index.js:321:12)
at next (C:\dev\infoscrn\node_modules\express\lib\router\index.js:261:10)
at C:\dev\infoscrn\node_modules\express\lib\router\index.js:603:15
at next (C:\dev\infoscrn\node_modules\express\lib\router\index.js:246:14)
First, try and update all your dependencies. There's been a recent version of Bluebird, which fixed an issue involving this warning.
Next, make sure you return from all your handlers.
Then, if you still get the warning (like I do) you can disable this specific warning. I chose to do so by setting BLUEBIRD_W_FORGOTTEN_RETURN=0 in my environment.
Don't disable warnings. They're there for a reason.
The typical pattern is that if your onfulfill or onreject handler causes a Promise to be constructed, it will return that Promise (or some chain derived from it) from the handler, so that the chain adopts the state of that Promise.
So Bluebird is keeping track of when it is running one of your handler functions, and also keeping track of when it's Promise constructor is called. If it determines that a Promise was created at any point while your handler is running (that includes anywhere down in the callstack), but that Promise was not returned from your handler, it issues this warning because it thinks you probably forgot to write the return statement.
So if you legitimately don't care about the Promise that was created inside the handler, all you have to do is explicitly return something from your handler. If you don't care about what is returned from your handler (i.e., if you don't care what value the Promise fulfills with), then simply return null. Whatever you return, the explicit return (specifically, a return value other than undefined) tells Bluebird that you think you know what you're doing, and it won't issue this warning.
Make sure that every place you have return statement which is the solution works for me.

nodejs require statement issue

I'm new to nodejs. I have the following files and code:
// file: myfunc.js
function myfunc() { return "myfunc()"; }
exports = myfunc;
and
// file: index.js
var mf = require("./myfunc");
var mfunc = mf();
console.log(mfunc);
When I run node index.js from command line, I get the error
var mfunc = mf()
^
TypeError: Object is not a function
Why do I get this error? I saw someone else's code which I paste below and I tried to follow the same approach of trying to get require() to return a function instead of an object.
// file: index.js from another app
var express = require('express');
var app = express();
How come require('express') can return a function but require('./myfunc') can't return a function?
It should be...
module.exports = myfunc;
... instead. Quoting the doc:
If you want the root of your module's export to be a function (such as
a constructor) or if you want to export a complete object in one
assignment instead of building it one property at a time, assign it to
module.exports instead of exports.

Resources