eslint/eslint · error · SyntaxError

Syntax error in selector "${selector}" at position ${err.loc

Error message

Syntax error in selector "${selector}" at position ${err.location.start.offset}: ${err.message}

What it means

Thrown by tryParseSelector when esquery fails to parse an AST selector string and the resulting error carries a location object (err.location.start.offset). The wrapper re-throws as a SyntaxError with the original selector, the 0-based offset of the failure, and esquery's message, chaining the original error as cause. Selectors that fail without a location are re-thrown unchanged.

Source

Thrown at lib/linter/esquery.js:272

	return null;
}

/**
 * Parses a raw selector string, and throws a useful error if parsing fails.
 * @param {string} selector The selector string to parse.
 * @returns {Object} An object (from esquery) describing the matching behavior of this selector
 * @throws {Error} An error if the selector is invalid
 */
function tryParseSelector(selector) {
	try {
		return esquery.parse(selector);
	} catch (err) {
		if (
			err.location &&
			err.location.start &&
			typeof err.location.start.offset === "number"
		) {
			throw new SyntaxError(
				`Syntax error in selector "${selector}" at position ${err.location.start.offset}: ${err.message}`,
				{
					cause: err,
				},
			);
		}
		throw err;
	}
}

/**
 * Parses a raw selector string, and returns the parsed selector along with specificity and type information.
 * @param {string} source A raw AST selector
 * @returns {ESQueryParsedSelector} A selector descriptor
 */
function parse(source) {
	if (selectorCache.has(source)) {
		return selectorCache.get(source);

View on GitHub (pinned to f131c034ad)

Solutions

  1. Read the reported offset and fix the selector at that character position.
  2. Validate selectors in isolation with require('esquery').parse(sel) during rule authoring.
  3. Cross-check the selector against the esquery syntax reference supported by your ESLint version.
  4. If building selectors dynamically, sanitize and unit-test the generated string.

Example fix

// before (malformed selector)
context.report({ node, message: 'x' });
// rule defined with selector: 'FunctionDeclaration >'

// after
// selector: 'FunctionDeclaration > BlockStatement'
Defensive patterns

Strategy: try-catch

Validate before calling

function isValidSelector(selector) {
  try { require('esquery').parse(selector.replace(/:exit$/u, '')); return true; } catch { return false; }
}

Type guard

function isParsableSelector(selector) { return typeof selector === 'string' && isValidSelector(selector); }

Try / catch

try { const parsed = require('esquery').parse(selector); } catch (err) {
  if (err.location && typeof err.location.start?.offset === 'number') {
    throw new SyntaxError(`Bad selector at offset ${err.location.start.offset}: ${err.message}`, { cause: err });
  }
  throw err;
}

Prevention

When it happens

Trigger: Writing an invalid esquery selector in a rule's visitor: 'FunctionDeclaration >', ':not(', 'Identifier[', or any malformed CSS-like selector. The error surfaces when ESLint parses rule selectors at load/config time.

Common situations: Authoring a custom ESLint rule with a typo'd selector; using esquery syntax not supported by the bundled version; copy-paste from CSS docs introducing unsupported pseudo-classes; a dynamic selector built from user input that produced malformed output.

Related errors


AI-assisted analysis of eslint/eslint@f131c034ad (2026-08-03). Data as JSON: /data/errors/ce1db1c0c18ac80f.json. Report an issue: GitHub.