Skip to content

Compile time errors being suppressed when using esm #2129

Description

@Stono

I really struggled to think of the correct title for this, so please edit it as required. I went down a rabbithole today whilst moving one of our apps to esm, as it was failing to start (with ts-node) due to the following node error:

❯ node --experimental-specifier-resolution=node --loader ts-node/esm lib/index.ts
node:internal/modules/run_main:115
    triggerUncaughtException(
    ^
[Object: null prototype] {
  [Symbol(nodejs.util.inspect.custom)]: [Function: [nodejs.util.inspect.custom]]
}

Node.js v22.5.1

Doesn't really give away much. It turned out however that the root caused we missed a return type on a promise eg Promise needed to be Promise<void>. This error was visible if you did a tsc, but ts-node was giving this output.

After gradually chipping away at the code to make a minimal example; i managed to reproduce it with a really simple bit of code that doesn't even technically have an error in it.

Assuming your code is in ./lib, create ./lib/index.ts:

import { SomeServer } from './server.js'

const webServer = new SomeServer()

and ./lib/server.ts:

export class SomeServer {}

If you try and start this; you'll get the error. The only thing "wrong" with this code is the fact that webServer is an unused variable. If i add console.log(webServer), eg:

import { SomeServer } from './server.js'

const webServer = new SomeServer()
console.log(webServer)

Then all is well:

❯ node --experimental-specifier-resolution=node --loader ts-node/esm lib/index.ts

SomeServer {}

Specifications

  • versions:
❯ ./node_modules/.bin/ts-node -vv
ts-node v10.9.2
node v22.5.1
compiler v5.3.3
  • tsconfig.json:
{
  "compilerOptions": {
    "lib": ["ES2022", "DOM"],
    "module": "ES2022",
    "target": "ES2022",
    "rootDir": "./",
    "outDir": "./built",
    "baseUrl": "./",
    "allowJs": false,
    "checkJs": false,
    "alwaysStrict": true,
    "noImplicitAny": true,
    "noImplicitThis": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictPropertyInitialization": true,
    "noEmitOnError": false,
    "sourceMap": false,
    "declaration": false,
    "strictBindCallApply": true,
    "noImplicitOverride": true,
    "noUncheckedIndexedAccess": true,
    "incremental": false,
    "skipDefaultLibCheck": true,
    "experimentalDecorators": true,
    "noUnusedLocals": true,
    "esModuleInterop": true,
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "allowSyntheticDefaultImports": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true
  },
  "include": ["lib/**/*.ts", "test/**/*.ts"],
  "exclude": ["node_modules/**/*"]
}
  • Operating system and version: Mac

Activity

  1. ethanhelliwell commented on Feb 6, 2025

    @ethanhelliwell

    Just a heads up that my error was due to the server.ts file having a variable in an "if" check which I hadn't initialized yet, e.g.

    app.get("/hut/:locationId", (req: Request, res: Response) => {
      const data = req.params.locationId;
      if (!location_id) { // <---- location_id was not not instantiated anywhere
        res.status(400).send("Bad Request: Missing locationId");
      } else {
        res.render('hut_template', data);
      }
    });
    

    The reason my tsc compilation wasn't catching was due to the same variable name "location_id" being instantiated in another .ts file so I was going mad to search for the cause...

  2. inoshadi commented on Apr 15, 2025

    @inoshadi

    I encountered this error when there was no use of a defined variable or function, it happens when I execute the script using ts-node, let's say node --loader ts-node/esm scripts/myscript.ts.
    And then I did some research and tried a simple trick, and the error went away.

    // the linter will help you with this
    const someVar: any // intended to use later, I want to check it out first
    // 
    const _falseCall = (_any: any) => { }; _falseCall(someVar);
    
    // what about this
    // You must use this function or it will trigger errors 
    const myFutureFunc = ()=> {
       // ...
       // lines of codes
       // ...
    }
    //  
    _falseCall(myFutureFunc); // I tried this and the error went away
    
    // ...
    // tons of lines
    // ...

    here is my .eslintrc.cjs:

    module.exports = {
      root: true,
      env: { browser: true, es2020: true },
      extends: [
        'eslint:recommended',
        'plugin:@typescript-eslint/recommended',
        'plugin:react-hooks/recommended',
      ],
      ignorePatterns: ['dist', '.eslintrc.cjs'],
      parser: '@typescript-eslint/parser',
      plugins: ['react-refresh'],
      rules: {
        'react-refresh/only-export-components': [
          'warn',
          { allowConstantExport: true },
        ],
      },
    }

    To conclude, if I know which variables or functions are not used, I try to comment out on them.
    However, there is a suggestion to enable type-aware lint rules, check it out here.
    I don't know if it helps.

  3. snowbytes commented on Sep 28, 2025

    @snowbytes

    This seems to be a general issue of how any UncaughtException is shown when ts-node/esm processes a file. It makes logs checking impossible as it always ends up showing the same cryptic result:

    node:internal/modules/run_main:123
        triggerUncaughtException(
        ^
    [Object: null prototype] {
      [Symbol(nodejs.util.inspect.custom)]: [Function: [nodejs.util.inspect.custom]]
    }

    The workaround to fix this is to make ts-node log TS errors to stderr instead of throwing exceptions (credits to this comment):

    /* tsconfig.json */
    {
      /* ... */
      "ts-node": {
        "logError": true,
        "pretty": true /* <= technically not required */
      }
    }
  4. rubs019 commented on Sep 30, 2025

    @rubs019

    @snowbytes this solution is working for me, thanks 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions