tree-sitter/tree-sitter · error · Error
Grammar's 'word' property must be a named rule.
Error message
Grammar's 'word' property must be a named rule.
What it means
Thrown by `grammar({...})` when the `word` option's callback result has no string `name` property. `word` designates the rule used for keyword extraction, and it must be a reference to a named rule — the DSL takes `.name` of the returned value directly, without normalizing it, so only a symbol like `$.identifier` (whose object has `name`) satisfies the check. Inline tokens, patterns, strings, or composite nodes have no `name` and throw. (If you return a rule name that doesn't exist, the proxy stub's `name` is `'ReferenceError'`, which passes this check and is caught by the follow-up check 'must be a valid rule name'.)
Source
Thrown at crates/generate/src/dsl.js:379
if (typeof options.extras !== "function") {
throw new Error("Grammar's 'extras' property must be a function.");
}
extras = options.extras
.call(ruleBuilder, ruleBuilder, baseGrammar.extras)
if (!Array.isArray(extras)) {
throw new Error("Grammar's 'extras' function must return an array.")
}
extras = extras.map(normalize);
}
let word = baseGrammar.word;
if (options.word) {
word = options.word.call(ruleBuilder, ruleBuilder).name;
if (typeof word != 'string') {
throw new Error("Grammar's 'word' property must be a named rule.");
}
if (word === 'ReferenceError') {
throw new Error("Grammar's 'word' property must be a valid rule name.");
}
}
let conflicts = baseGrammar.conflicts;
if (options.conflicts) {
if (typeof options.conflicts !== "function") {
throw new Error("Grammar's 'conflicts' property must be a function.");
}
const baseConflictRules = baseGrammar.conflicts.map(conflict => conflict.map(sym));
const conflictRules = options.conflicts.call(ruleBuilder, ruleBuilder, baseConflictRules);
if (!Array.isArray(conflictRules)) {
throw new Error("Grammar's conflicts must be an array of arrays of rules.");View on GitHub (pinned to dff1fd868c)
Solutions
- Define the word token as a named rule, then reference the symbol: `identifier: $ => /[a-zA-Z_]\w*/` plus `word: $ => $.identifier`.
- Keep `word` pointing at exactly one named symbol — no `token()`, `seq()`, or literals in the return slot.
- If you got 'must be a valid rule name' instead, the referenced rule doesn't exist — check spelling/placement in `rules`.
Example fix
// before
word: $ => token(/[a-zA-Z_]\w*/)
// after
rules: {
identifier: $ => /[a-zA-Z_]\w*/,
...
},
word: $ => $.identifier Defensive patterns
Strategy: validation
Validate before calling
function validateWordOption(options) {
if (options.word) {
if (typeof options.word !== 'function') throw new Error('word must be a function');
const $ = new Proxy({}, { get: (_, k) => ({ type: 'SYMBOL', name: k }) });
const out = options.word($, undefined);
if (typeof out?.name !== 'string' || out.name === 'ReferenceError') {
throw new Error('word must return a named rule symbol, e.g. $ => $.identifier');
}
}
} Type guard
const isNamedSymbol = (v) => typeof v === 'object' && v !== null && typeof v.name === 'string' && v.name !== 'ReferenceError';
Prevention
- Define the word token as its own named rule (e.g. `identifier`) and set `word: $ => $.identifier`.
- Never inline `token(...)` or regexes in the `word` slot — the DSL reads `.name` directly.
- Check the follow-up 'valid rule name' error too: it means the referenced rule doesn't exist in `rules`.
When it happens
Trigger: `word: $ => token(/[a-zA-Z_]\w*/)` (inline token object has no `.name`); `word: $ => 'identifier'` (string primitive); `word: $ => seq(...)` or `choice(...)` (composite node); `word: $ => $.undefined_rule` (throws the follow-up 'valid rule name' error instead, at line 382).
Common situations: Authors inline the identifier token directly in the `word` slot instead of defining it as a named rule first; refactoring an inline identifier into `word` without moving the token into its own rule; grammars where the word rule is built by a helper returning a node rather than a symbol.
Related errors
- Grammar's 'externals' property must be a function.
- Grammar's 'externals' property must return an array of rules
- Grammar's 'name' property must be a string.
- Grammar's 'name' property must not start with a digit and ca
- Base grammar's 'name' property must be a string.
AI-assisted analysis of tree-sitter/tree-sitter@dff1fd868c (2026-08-16).
Data as JSON: /api/errors/59a5a985d7a7ab7b.
Report an issue: GitHub.