[Bug] Mikro-ORM return "Cannot read properties of undefined"
What happened?
When using MySQL, Mikro-ORM can't create migration due the following error :
TypeError: Cannot read properties of undefined (reading 'BOT_OWNER_ID')
at Object.<anonymous> (C:\Users\Josh\Documents\Projects\RoseBot\src\configs\general.ts:8:15)
at Module._compile (node:internal/modules/cjs/loader:1546:14)
at Module.m._compile (C:\Users\Josh\Documents\Projects\RoseBot\node_modules\ts-node\src\index.ts:1618:23)
at node:internal/modules/cjs/loader:1698:10
at Object.require.extensions.<computed> [as .ts] (C:\Users\Josh\Documents\Projects\RoseBot\node_modules\ts-node\src\index.ts:1621:12)
at Module.load (node:internal/modules/cjs/loader:1303:32)
at Function._load (node:internal/modules/cjs/loader:1117:12)
at TracingChannel.traceSync (node:diagnostics_channel:322:14)
at wrapModuleLoad (node:internal/modules/cjs/loader:218:24)
at Module.require (node:internal/modules/cjs/loader:1325:12)
Credit : @JoshCantCode Cf : Discord support thread
Reproduction
- Init a new bot
- Setup
.envfile - Change database config to use a MySQL database
- Run any Mikro-ORM command
Code of Conduct
- [ ] I agree to follow this project's Code of Conduct
Update to this. It seems to not only be a MySQL issue. Just tried creating one with Postgres and it also occurs! Doesn't really help much but at least we know the issue isn't caused by just MySQL
I’ve personally tested this with Postgres, but the same error persists. It seems that when running mikro-orm migration:* commands, the .env file isn’t loaded properly—even though the repository follows the recommended approach from MikroORM’s official documentation.
The relevant changes in tscord were introduced in:
However, even in a fresh tscord project, the .env file fails to load correctly—at least in:
And I assume other part of the project might also need modification as long as @env is involved further.
It looks like mikro-orm cannot properly read tsconfig.json therefore paths in compilerOptions cannot be processed or loaded.
I’d be happy to open a PR with the proposed changes (for demonstration, here I only show the modified api.ts, but to make it work, similar changes in general.ts are also needed). However, I’m unsure if this adjustment aligns with the original intent of using @env or maintains the type constraints properly.
Before
import { env } from '@/env'
export const apiConfig: APIConfigType = {
enabled: false, // is the API server enabled or not
port: env.API_PORT || 4000,
}
After
import 'dotenv/config'
import process from 'node:process'
// import { env } from '@/env'
const env = process.env
export const apiConfig: APIConfigType = {
enabled: false, // is the API server enabled or not
port: ((env.API_PORT) as unknown) as number || 4000, // very bad type casting ;(
}
These are not elegant edits but in the meantime you get a workaround to make it through.
@barthofu, let me know if you’d like me to proceed or if there’s a preferred way to handle this.
There’s a circular dependency: environment.ts imports from @/configs, and configs import env, causing generalConfig to be undefined.
Fix: remove the config imports from environment.ts and compute needed values inline.
In environment.ts
import process from 'node:process'
import { cleanEnv, num, str } from 'envalid'
// Remove the imports that cause circular dependency
// import { apiConfig, generalConfig, mikroORMConfig } from '@/configs'
Then (still in environment.ts)
// Move the config-dependent logic to where it's actually called
// This will be called from main.ts after all configs are loaded
export function checkEnvironmentVariables() {
// Import dynamically to avoid circular dependency
const { apiConfig, generalConfig, mikroORMConfig } = require('@/configs')
...
In main.ts, changing from
async function init() {
const logger = await resolveDependency(Logger)
// check environment variables
checkEnvironmentVariables()
...
to
async function init() {
const logger = await resolveDependency(Logger)
// check environment variables
await checkEnvironmentVariables()
...