How to check eslint errors

Run npx eslint . in the project root. Each problem prints as file, line, column, severity, message and rule id, and the run ends with a count. ESLint exits 1 when it found at least one error and 0 when it found only warnings, which is the part that surprises people reading a CI log.

Why check this

A lint run belongs in the pull request gate, beside the type check, and in CI on every push. It catches the defects a type checker has no opinion about: a comparison that coerces, a variable assigned and never read, a promise nobody awaited.

The failure it prevents is a rule that has been shouting for months into a log nobody reads. A warning costs nothing at merge time and exits 0, so a team can carry hundreds of them while believing the gate is closed. This procedure separates what ESLint reports from what ESLint enforces.

Prerequisites

// eslint.config.js
import js from '@eslint/js';

export default [
  js.configs.recommended,
  {
    languageOptions: { globals: { console: 'readonly' } },
    rules: {
      'no-console': 'warn',
      eqeqeq: 'error',
    },
  },
];
// src/cart.js  two errors
export function total(lines) {
  const rate = 1.2;
  let sum = 0;
  for (const line of lines) {
    if (line.qty == '0') continue;
    sum += line.price * line.qty;
  }
  return sum;
}
// src/report.js  one warning, no errors
export function report(rows) {
  console.log('rows', rows.length);
  return rows.length;
}
// src/parse.ts  broken, and the config does not match it
export function parse(raw: string): number {
  return undefinedHelper(raw);
}

Steps

  1. Step 1.

    Read the ESLint version the project resolves to. The rule set and the config format both depend on it.

    npx eslint --version
    
    v10.10.0
  2. Step 2.

    Lint the project and read the exit code in the same line.

    npx eslint .; echo "exit=$?"
    
    D:\how2check\scratch\lintq\src\cart.js
    2:9   error  'rate' is assigned a value but never used  no-unused-vars
    5:18  error  Expected '===' and instead saw '=='        eqeqeq
    
    D:\how2check\scratch\lintq\src\report.js
    2:3  warning  Unexpected console statement  no-console
    
    ✖ 3 problems (2 errors, 1 warning)
    
    exit=1

    The last column is the rule id. It is the only part worth quoting in a ticket, because the message text changes between versions.

  3. Step 3.

    Lint the file that has a warning and no error, and read the exit code again.

    npx eslint src/report.js; echo "exit=$?"
    
    D:\how2check\scratch\lintq\src\report.js
    2:3  warning  Unexpected console statement  no-console
    
    ✖ 1 problem (0 errors, 1 warning)
    
    exit=0

    ESLint printed a problem and reported success. A CI step that reads only the status treats this run as clean.

  4. Step 4.

    Make warnings count.

    npx eslint src/report.js --max-warnings 0; echo "exit=$?"
    
    D:\how2check\scratch\lintq\src\report.js
    2:3  warning  Unexpected console statement  no-console
    
    ✖ 1 problem (0 errors, 1 warning)
    
    ESLint found too many warnings (maximum: 0).
    exit=1

    Same output, same warning, different status. This is the flag that turns a report into a gate.

  5. Step 5.

    List the files the run actually read, rather than the files it reported on.

    npx eslint . --format json | node -e "let s='';process.stdin.on('data',d=>s+=d).on('end',()=>JSON.parse(s).forEach(r=>console.log(r.filePath)))"
    
    D:\how2check\scratch\lintq\eslint.config.js
    D:\how2check\scratch\lintq\src\cart.js
    D:\how2check\scratch\lintq\src\report.js

    Three files. src/parse.ts is not among them, and step 2 said nothing about it.

  6. Step 6.

    Point ESLint straight at the file it skipped.

    npx eslint src/parse.ts; echo "exit=$?"
    
    D:\how2check\scratch\lintq\src\parse.ts
    0:0  warning  File ignored because no matching configuration was supplied
    
    ✖ 1 problem (0 errors, 1 warning)
    
    exit=0

    Naming the file does not lint it. The refusal arrives as a warning at line 0, and the run still exits 0.

How to read the result

| What you see | What it means | What to do | | --- | --- | --- | | No output at all, exit 0 | Every matched file passed every enabled rule | Confirm the matched file list with step 5 before believing it. | | error rows, exit 1 | At least one rule set to error fired | Fix them. --fix handles the mechanical ones. | | Only warning rows, exit 0 | Rules are reporting, nothing is enforced | Add --max-warnings 0 to the CI command, or raise the rules to error. | | File ignored because no matching configuration was supplied | No config entry matches that extension | Add a files entry and a parser for it. Until then the file is unlinted. | | exit 2 with a stack trace | The config itself failed to load | Read the module name in the error. A missing config dependency looks nothing like a lint failure. |

Common mistakes

Sign: CI is green while the log shows problems.Cause: ESLint exits 1 for errors and 0 for warnings. Step 3 prints a problem and exits 0, so a pipeline that checks only the status passes a file it just complained about. `--max-warnings 0` is the only thing that closes that gap, and it has to be on the CI command, not in the config file.
Sign: A file with obvious defects is never mentioned, and naming it directly changes nothing.Cause: A flat config lints `.js`, `.mjs` and `.cjs` unless an entry says otherwise, so `src/parse.ts` is skipped in step 5 and refused in step 6. The refusal is a warning at line 0:0, which means an explicit `npx eslint src/parse.ts` still exits 0. Nothing in the run reads as a failure.
Sign: `npx eslint` fails with ERR_MODULE_NOT_FOUND on a machine where it worked yesterday.Cause: The config is JavaScript and imports real packages. ESLint 9 and later no longer ship `@eslint/js` as a resolvable dependency of the CLI, so a config that imports it needs it installed beside ESLint. The exit code is 2, not 1, and no file was linted.
Sign: Two developers get different results from the same command.Cause: `npx eslint` prefers the local install and falls back to whatever is global or fetchable. Step 1 is not a formality: run it on both machines, and keep ESLint in devDependencies so the resolved version is the one in the lockfile.

What to check next

FAQ

How do I check my ESLint version?

npx eslint --version prints the version the project resolves, v10.10.0 here. Prefer it to a global eslint --version, which can report a different install. The config format changed at version 9, so the number decides whether eslint.config.js or .eslintrc is read.

Why does ESLint exit 0 when it printed problems?

Warnings do not fail the run. Only a rule set to error moves the exit code to 1. Add --max-warnings 0 to make the count fail the command, as step 4 shows.

How do I see only the errors?

npx eslint . --quiet suppresses the warning rows and reports errors alone. Combined with --max-warnings 0 the warnings are still counted: on src/report.js that pair prints no rows and exits 1.

Does ESLint check TypeScript files?

Not with the config above. TypeScript needs typescript-eslint, a parser entry and a files pattern that includes the extension. Without them the files are skipped silently, which step 5 makes visible.

Can ESLint fix what it reports?

Some of them. A fixable rule does not make every violation fixable: --fix-dry-run --format json on src/cart.js reports fixableErrorCount: 0, because rewriting line.qty == '0' as === would change the result. Run the check again after a fix pass.

Verified

Verified by Maks Vernyeslint 10.10.0node 22.23.2

Each output block is what the command above it printed on that date, on the host named in the step. Figures read from a live site move between runs. Compare the shape of the answer rather than the digits, and see the methodology for how a page is re-verified.

basic7 minpublished updated Maks Verny