tree-sitter/tree-sitter · error · Error

Grammar must have at least one rule.

Error message

Grammar must have at least one rule.

What it means

After merging `options.rules` over the base grammar's rules, the DSL requires at least one rule before assembling the grammar object. An empty rules object (or a missing `rules` key in a standalone grammar) leaves nothing to generate a parser from, so this throws right before the grammar is returned.

Source

Thrown at crates/generate/src/dsl.js:474

  let precedences = baseGrammar.precedences;
  if (options.precedences) {
    if (typeof options.precedences !== "function") {
      throw new Error("Grammar's 'precedences' property must be a function");
    }
    precedences = options.precedences.call(ruleBuilder, ruleBuilder, baseGrammar.precedences);
    if (!Array.isArray(precedences)) {
      throw new Error("Grammar's precedences must be an array of arrays of rules.");
    }
    precedences = precedences.map(list => {
      if (!Array.isArray(list)) {
        throw new Error("Grammar's precedences must be an array of arrays of rules.");
      }
      return list.map(normalize);
    });
  }

  if (Object.keys(rules).length === 0) {
    throw new Error("Grammar must have at least one rule.");
  }

  return {
    grammar: {
      name,
      inherits,
      word,
      rules,
      extras,
      conflicts,
      precedences,
      externals,
      inline,
      supertypes,
      reserved,
    },
  };
}

View on GitHub (pinned to dff1fd868c)

Solutions

  1. Add a `rules` object with at least one named rule, e.g. `source_file: $ => repeat($.thing)`.
  2. Check that `rules:` sits at the top level of the options object.
  3. When inheriting, require the base grammar before `grammar(base, {...})` so its rules merge in.

Example fix

// before
module.exports = grammar({
  name: 'empty',
});

// after
module.exports = grammar({
  name: 'empty',
  rules: {
    source_file: $ => repeat(/\w+/),
  },
});
Defensive patterns

Strategy: validation

Validate before calling

const options = { name: 'mylang', rules: { /* ... */ } };
if (Object.keys(options.rules ?? {}).length === 0) {
  throw new Error('grammar must define at least one rule');
}
module.exports = grammar(options);

Prevention

When it happens

Trigger: `module.exports = grammar({ name: 'x' })` with no `rules` key. `rules: {}` after a botched edit. Rules accidentally nested inside another option or defined under the wrong key.

Common situations: Truncated or badly merged grammar.js files. Generating a new grammar from a minimal template before writing any rules.

Related errors


AI-assisted analysis of tree-sitter/tree-sitter@dff1fd868c (2026-08-16). Data as JSON: /api/errors/8ce8fba71fba2d48. Report an issue: GitHub.