denoland/deno · error · Error

Expected token '${token}', but got '${this.token}'.\n\n${thi

Error message

Expected token '${token}', but got '${this.token}'.\n\n${this.input}\n${" ".repeat(this.i)}^

What it means

Thrown by Lexer.expect() in cli/js/40_lint_selector.js when the selector grammar requires a specific token but a different one (printed as its numeric token id) is next. The message echoes the full input and a caret pointing at the lexer position, so you can see exactly where parsing derailed.

Source

Thrown at cli/js/40_lint_selector.js:140

  i = -1;

  value = "";

  /**
   * @param {string} input
   */
  constructor(input) {
    this.input = input;
    this.step();
    this.next();
  }

  /**
   * @param {number} token
   */
  expect(token) {
    if (this.token !== token) {
      throw new Error(
        `Expected token '${token}', but got '${this.token}'.\n\n${this.input}\n${
          " ".repeat(this.i)
        }^`,
      );
    }
  }

  /**
   * @param {number} token
   */
  readAsWordUntil(token) {
    const s = this.i;
    while (this.token !== Token.EOF && this.token !== token) {
      this.next();
    }

    this.start = s;
    this.end = this.i - 1;

View on GitHub (pinned to 89f33cbef2)

Solutions

  1. Read the caret line in the message — it marks the exact character where the expected token was not found
  2. Balance the selector: every '[' has ']' and every '(' has ')'
  3. Split overly long selectors into multiple visitor keys or move conditions into the callback

Example fix

// before
"MemberExpression[property.name === \"length\"]"(node) {},

// after
"MemberExpression[property.name=\"length\"]"(node) {},
Defensive patterns

Strategy: try-catch

Validate before calling

// cheap bracket-balance check for hand-built selector strings
function bracketsBalanced(sel) {
  const pairs = { "[": "]", "(": ")" };
  const stack = [];
  for (const ch of sel) {
    if (pairs[ch]) stack.push(pairs[ch]);
    else if (Object.values(pairs).includes(ch) && stack.pop() !== ch) return false;
  }
  return stack.length === 0;
}

Try / catch

try {
  lintFixtureWithPlugin(plugin); // run deno lint on a scratch file
} catch (err) {
  if (err instanceof Error && err.message.startsWith("Expected token")) {
    // the message contains input + caret; fix the selector at the caret position
    console.error(err.message);
  }
  throw err;
}

Prevention

When it happens

Trigger: Malformed visitor-key selectors: unbalanced or missing brackets/parens such as ":has(CallExpression", "ObjectExpression[", "VariableDeclarator > "; missing closing brace in ":nth-child(2"; stray characters where a word or bracket was expected.

Common situations: Hand-writing long compound selectors in a rule's create() return object; a visitor key with a typo after refactoring; dynamically concatenating selector fragments and dropping a closing bracket.

Related errors


AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16). Data as JSON: /api/errors/2920fa88c755a6bb. Report an issue: GitHub.