tree-sitter/tree-sitter · error · Error

Grammar's 'name' property must be a string.

Error message

Grammar's 'name' property must be a string.

What it means

Thrown by `grammar({...})` when the `name` option is not a string. The grammar name drives the generated language name and parser symbols (`tree_sitter_<name>`, `TS_PARSER_NAME`), so it is mandatory and must be a string. Omitting `name` entirely (undefined), passing null, or computing it from a non-string source all fail here — this fires before the identifier-format check on the next lines.

Source

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

  const ruleMap = {};
  for (const key of Object.keys(options.rules)) {
    ruleMap[key] = true;
  }
  for (const key of Object.keys(baseGrammar.rules)) {
    ruleMap[key] = true;
  }
  for (const external of externals) {
    if (typeof external.name === 'string') {
      ruleMap[external.name] = true;
    }
  }

  const ruleBuilder = RuleBuilder(ruleMap);

  const name = options.name;
  if (typeof name !== "string") {
    throw new Error("Grammar's 'name' property must be a string.");
  }

  if (!/^[a-zA-Z_]\w*$/.test(name)) {
    throw new Error("Grammar's 'name' property must not start with a digit and cannot contain non-word characters.");
  }

  if (inherits && typeof inherits !== "string") {
    throw new Error("Base grammar's 'name' property must be a string.");
  }

  if (inherits && !/^[a-zA-Z_]\w*$/.test(name)) {
    throw new Error("Base grammar's 'name' property must not start with a digit and cannot contain non-word characters.");
  }

  const rules = Object.assign({}, baseGrammar.rules);
  if (options.rules) {
    if (typeof options.rules !== "object") {
      throw new Error("Grammar's 'rules' property must be an object.");

View on GitHub (pinned to dff1fd868c)

Solutions

  1. Add a string name, snake_cased: `name: 'my_language'`.
  2. Keep it consistent with the package name: package `tree-sitter-my-language` uses `name: 'my_language'`.
  3. If the name is computed, fall back to a literal default rather than shipping undefined.

Example fix

// before
module.exports = grammar({
  rules: { source_file: $ => $.expr }
});

// after
module.exports = grammar({
  name: 'my_language',
  rules: { source_file: $ => $.expr }
});
Defensive patterns

Strategy: validation

Validate before calling

function validateGrammarOptions(options) {
  if (typeof options.name !== 'string') {
    throw new Error("Grammar's 'name' must be a snake_case string, e.g. 'my_language'");
  }
}

Type guard

const hasValidName = (o) => typeof o.name === 'string';

Prevention

When it happens

Trigger: `grammar({ rules: {...} })` with no `name` key at all; `name: null`; `name: 123`; a name imported from a module that exported undefined (typo'd import name that didn't fail at load); inheriting grammars where the author assumed the base grammar's name carries over.

Common situations: Scaffolding a new grammar from a template and deleting or renaming the name field; grammars that compute `name` from package metadata with a failed lookup; inheriting grammars forgetting that the derived grammar still needs its own `name`.

Related errors


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