"Cannot read 'name' of undefined" happens occasionally when incorrect import order
The issue is quite vague.
I am creating the project (code). It is a back-end, so I have an entry point to my server and a cli script that populates the database.
The problem is that my UserModel, that has a single dependency (a connection), can be container.get() from the CLI database script and fails when I try to start the server within the same project.
All annotations are set, 'reflect-metadata' is imported (even tried doing it several times :) ) and I see no differences between server and CLI scripts (regarding Inversify).
Expected Behavior
The UserModel instance can be acquired under any circumstances (see code).
Current Behavior
When I try to import from server scripts, I get Cannot read 'name' of undefined error:
TypeError: Cannot read property 'name' of undefined
at Object.getFunctionName (/home/bogdan/nure/courseProject/DrOwn-server/node_modules/inversify/lib/utils/serialization.js:94:11)
at Object.getDependencies (/home/bogdan/nure/courseProject/DrOwn-server/node_modules/inversify/lib/planning/reflection_utils.js:11:43)
at /home/bogdan/nure/courseProject/DrOwn-server/node_modules/inversify/lib/planning/planner.js:106:51
at Array.forEach (<anonymous>)
at _createSubRequests (/home/bogdan/nure/courseProject/DrOwn-server/node_modules/inversify/lib/planning/planner.js:94:20)
at Object.plan (/home/bogdan/nure/courseProject/DrOwn-server/node_modules/inversify/lib/planning/planner.js:136:9)
at /home/bogdan/nure/courseProject/DrOwn-server/node_modules/inversify/lib/container/container.js:317:37
at Container._get (/home/bogdan/nure/courseProject/DrOwn-server/node_modules/inversify/lib/container/container.js:310:44)
at Container.get (/home/bogdan/nure/courseProject/DrOwn-server/node_modules/inversify/lib/container/container.js:230:21)
at Object.<anonymous> (/home/bogdan/nure/courseProject/DrOwn-server/dist/services/authentication.service.js:21:41)
at Module._compile (internal/modules/cjs/loader.js:688:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:699:10)
at Module.load (internal/modules/cjs/loader.js:598:32)
at tryModuleLoad (internal/modules/cjs/loader.js:537:12)
at Function.Module._load (internal/modules/cjs/loader.js:529:3)
at Module.require (internal/modules/cjs/loader.js:636:17)
Possible Solution
None. I have tried all the pieces of advice from #584, #488 and #961 (the closest one, I think it is similar to mine).
Steps to Reproduce (for bugs)
The problem is I have tried to create minimalistic example that shows this error, but every time I tried to do this (outside and inside) the project I failed. In fact, it works even within current project (from the CLI database script). So my example is this project (sorry to bother you with >3000 dependencies :) ). Steps to start the project:
git clone https://github.com/shevchenkobn/DrOwn-server.gitgit checkout f676ae87b13a8372e00401e2cd1e5bc04810032bnpm inpm start(the JS code is built and up-to-date; if you want to rebuild it runnpm run build. In this case you would probably installdevDependenciesbynpm i -Dandnpm run npm:g:devornpm run npm:g:dev:win- global packages for development)- See the error.
Context
Possibly, the issue is connected with sideeffects of either Inversify with reflect-metadata or some other packages and may be relevant to other developers. Again, the issue is similar to #961
I really liked your package but, unfortunately, I have to use some alternative DI library. Hope the issues is resolved and I will get back to Inversify.
Your Environment
- Version used: 5.0.1
- Environment name and version (e.g. Chrome 39, node.js 5.4): Node.JS v10.13.0, TypeScript Version 3.2.0-dev.20181110
- Operating System and version (desktop or mobile): Ubuntu 18.04.1 LTS
- Link to your project: https://github.com/shevchenkobn/DrOwn-server/tree/f676ae87b13a8372e00401e2cd1e5bc04810032b
Stack trace
TypeError: Cannot read property 'name' of undefined
at Object.getFunctionName (/home/bogdan/nure/courseProject/DrOwn-server/node_modules/inversify/lib/utils/serialization.js:94:11)
at Object.getDependencies (/home/bogdan/nure/courseProject/DrOwn-server/node_modules/inversify/lib/planning/reflection_utils.js:11:43)
at /home/bogdan/nure/courseProject/DrOwn-server/node_modules/inversify/lib/planning/planner.js:106:51
at Array.forEach (<anonymous>)
at _createSubRequests (/home/bogdan/nure/courseProject/DrOwn-server/node_modules/inversify/lib/planning/planner.js:94:20)
at Object.plan (/home/bogdan/nure/courseProject/DrOwn-server/node_modules/inversify/lib/planning/planner.js:136:9)
at /home/bogdan/nure/courseProject/DrOwn-server/node_modules/inversify/lib/container/container.js:317:37
at Container._get (/home/bogdan/nure/courseProject/DrOwn-server/node_modules/inversify/lib/container/container.js:310:44)
at Container.get (/home/bogdan/nure/courseProject/DrOwn-server/node_modules/inversify/lib/container/container.js:230:21)
at Object.<anonymous> (/home/bogdan/nure/courseProject/DrOwn-server/dist/services/authentication.service.js:21:41)
at Module._compile (internal/modules/cjs/loader.js:688:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:699:10)
at Module.load (internal/modules/cjs/loader.js:598:32)
at tryModuleLoad (internal/modules/cjs/loader.js:537:12)
at Function.Module._load (internal/modules/cjs/loader.js:529:3)
at Module.require (internal/modules/cjs/loader.js:636:17)
I have fixed this issue.
If you have a complex project with lots of dependencies and you don't have to worry about the way they are resolved just add import './pass/to/your/di.container'; at the beginning of the file. di.container in this context is file where you create container and add all dependencies there. Example: https://github.com/shevchenkobn/NewCMMS-server/blob/master/src/di/container.ts
Explanation: tl;dr: check your import tree manually. Consider moving objects managed by your DI into separate files in a type-per-file manner. It may be issue with circular imports or similar.
Node modules that have your @injectables probably import their @inject types directly (not for instantiation). Imports are done at the beginning of the file when @injectable type is not even declared. So if your module with @injectable is imported in DI container module, it may get an undefined instead of your @injectable. That is what I had. Inversify tries to report the problem and fails.
Maybe a safeguard should be added to the library? It would be better to check if the type is undefined and report it before trying to read its name.
Something like Error: The dependency Symbol.for(type) is not defined. Consider reordering imports or import your container in the entry-point file.
@shevchenkobn I've run into this issue recently. Could you elaborate on what you mean by:
"If you have a complex project with lots of dependencies and you don't have to worry about the way they are resolved just add import './pass/to/your/di.container'; at the beginning of the file."?
@shevchenkobn I've run into this issue recently. Could you elaborate on what you mean by:
"If you have a complex project with lots of dependencies and you don't have to worry about the way they are resolved just add import './pass/to/your/di.container'; at the beginning of the file."?
I have updated the previous post. Please, reread the passage you quoted and tl;dr section.
@shevchenkobn I am sorry but after reading your answer multiple times and checking your code and jimador one, I still do not understand how to fix the issue.
Here is what I have :
// inversify.config.ts
import {TYPES} from "./Types";
import {Container} from "inversify";
import {Config} from "../models/Config";
import {ZoneService} from "../services/zones/ZoneService";
import {IZoneService} from "../services/interfaces/IZoneService";
const DI = new Container()
DI.bind<Config>(TYPES.Config).toConstantValue(config() as Config)
DI.bind<IZoneService>(TYPES.ZoneService).to(ZoneService).inSingletonScope()
export {DI}
// Types.ts
import "reflect-metadata";
export const TYPES = {
Config: Symbol.for("Config"),
ZoneService: Symbol.for("ZoneService"),
}
// ZoneService.ts
import {TYPES} from "../../di/Types";
import {inject, injectable} from "inversify";
import {Config} from "../../models/Config";
import {IZoneService} from "../interfaces/IZoneService";
const TAG = "ZoneService"
@injectable()
class ZoneService implements IZoneService {
public constructor(
@inject(TYPES.Config) config: Config
) {
...
}
...
}
// ZoneInteractor.js
const {DI} = require("../di/inversify.config");
const {IZoneService} = require("../services/interfaces/IZoneService");
const {TYPES} = require("../di/Types");
class ZoneInteractor {
async run() {
...
const zoneService = DI.get<IZoneService>(TYPES.ZoneService) // Issue 1
zoneService.doSomething() // Issue 2
}
}
Issue 1 : I am getting Cannot convert a Symbol value to a number on the line, if anyone has an insight here, it would be very helpful.
If I change TYPES object for string only like this :
export const TYPES = {
Config: "Config",
ZoneService: "ZoneService",
}
I am getting the issue related to this thread,
Issue 2 : zoneService.doSomething is not a function, do you understand what could be the issue with imports here ?
Hello. I am in a trip, so will be brief.
The issue is with library consumers code, with my code in this case. I suggest checking the dependency for nullish values before getting name property and throwing a more helpful exception (see comments above). I think giving the name of faulty dependency with a start trace can really speed up circular dependencies detection in user's code.
I don't think the library can resolve this issue any other way than throwing a more helpful error.
On Wed, Aug 11, 2021, 3:12 AM Thomas Perraut @.***> wrote:
@shevchenkobn https://github.com/shevchenkobn I am sorry but after reading your answer multiple times and checking your code and jimador one, I still do not understand how to fix the issue.
Here is what I have :
// inversify.config.tsimport {TYPES} from "./Types";import {Container} from "inversify";import {Config} from "../models/Config";import {ZoneService} from "../services/zones/ZoneService";import {IZoneService} from "../services/interfaces/IZoneService"; const DI = new Container()DI.bind<Config>(TYPES.Config).toConstantValue(config() as Config)DI.bind<IZoneService>(TYPES.ZoneService).to(ZoneService).inSingletonScope() export {DI} // Types.tsimport "reflect-metadata"; export const TYPES = { Config: Symbol.for("Config"), ZoneService: Symbol.for("ZoneService"),} // ZoneService.tsimport {TYPES} from "../../di/Types";import {inject, injectable} from "inversify";import {Config} from "../../models/Config";import {IZoneService} from "../interfaces/IZoneService"; const TAG = "ZoneService"
@injectable()class ZoneService implements IZoneService {
public constructor( @inject(TYPES.Config) config: Config ) { ... } ...} // ZoneInteractor.jsconst {DI} = require("../di/inversify.config");const {IZoneService} = require("../services/interfaces/IZoneService");const {TYPES} = require("../di/Types"); class ZoneInteractor { async run() { ... const zoneService = DI.get<IZoneService>(TYPES.ZoneService) // Issue 1 zoneService.doSomething() // Issue 2 }}
Issue 1 : I am getting Cannot convert a Symbol value to a number on the line, if anyone has an insight here, it would be very helpful.
If I change TYPES object for string only like this :
export const TYPES = { Config: "Config", ZoneService: "ZoneService",}
I am getting the issue related to this thread, Issue 2 : zoneService.doSomething is not a function, do you understand what could be the issue with imports here ?
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/inversify/InversifyJS/issues/1005#issuecomment-896395949, or unsubscribe https://github.com/notifications/unsubscribe-auth/AF23D62L4DTOXNLCLABPU3DT4G553ANCNFSM4GGIDUQA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&utm_campaign=notification-email .
@sergeyzenchenko thank you for dropping by, my issue was way simpler than I thought, I just added a <Type> in a js file, breaking everything at runtime. I described the issue here : #1364
I found the same problem. My problem has been solved, found out that other classes were imported before importing the container configuration file。
export * from './loader'
export * from './add.command'
export * from './create.command'
export * from './info.command'
export * from './open.command'```
The above is how I write it. The first line introduces the IOC container, and the last few lines are injectable classes