neoclide/coc.nvim · error

`tokenModifier` is not in the provided legend

Error message

`tokenModifier` is not in the provided legend

What it means

Each string token modifier must exist in the legend's tokenModifiers array so it can be converted to a bitmask. If any modifier string in the modifiers array is unknown to the legend, the builder throws this error.

Source

Thrown at src/model/semanticTokensBuilder.ts:95

  private _push(range: Range, tokenType: string, tokenModifiers?: string[]): void {
    if (!this._hasLegend) {
      throw new Error('Legend must be provided in constructor')
    }
    if (range.start.line !== range.end.line) {
      throw new Error('`range` cannot span multiple lines')
    }
    if (!this._tokenTypeStrToInt.has(tokenType)) {
      throw new Error('`tokenType` is not in the provided legend')
    }
    const line = range.start.line
    const char = range.start.character
    const length = range.end.character - range.start.character
    const nTokenType = this._tokenTypeStrToInt.get(tokenType)!
    let nTokenModifiers = 0
    if (tokenModifiers) {
      for (const tokenModifier of tokenModifiers) {
        if (!this._tokenModifierStrToInt.has(tokenModifier)) {
          throw new Error('`tokenModifier` is not in the provided legend')
        }
        const nTokenModifier = this._tokenModifierStrToInt.get(tokenModifier)!
        nTokenModifiers |= (1 << nTokenModifier) >>> 0
      }
    }
    this._pushEncoded(line, char, length, nTokenType, nTokenModifiers)
  }

  private _pushEncoded(line: number, char: number, length: number, tokenType: number, tokenModifiers: number): void {
    if (this._dataIsSortedAndDeltaEncoded && (line < this._prevLine || (line === this._prevLine && char < this._prevChar))) {
      // push calls were ordered and are no longer ordered
      this._dataIsSortedAndDeltaEncoded = false

      // Remove delta encoding from data
      const tokenCount = (this._data.length / 5) | 0
      let prevLine = 0
      let prevChar = 0
      for (let i = 0; i < tokenCount; i++) {

View on GitHub (pinned to 50e974d969)

Solutions

  1. Include all server-declared modifiers in the tokenModifiers legend array
  2. Filter unknown modifiers before pushing: modifiers.filter(m => legend.tokenModifiers.includes(m))
  3. Sync the legend from the server's SemanticTokensLegend rather than hand-writing it

Example fix

// before
builder.push(range, 'function', ['static']) // 'static' not in legend
// after
const known = ['static'].filter(m => legend.tokenModifiers.includes(m))
builder.push(range, 'function', known)
Defensive patterns

Strategy: validation

Validate before calling

const safeModifiers = modifiers.filter(m => legend.tokenModifiers.includes(m))

Type guard

function areKnownModifiers(ms: string[], legend: SemanticTokensLegend): boolean {
  return ms.every(m => legend.tokenModifiers.includes(m))
}

Try / catch

try {
  builder.push(range, tokenType, modifiers)
} catch (e) {
  if (e.message.includes('tokenModifier` is not in the provided legend')) {
    console.warn('Unknown token modifiers dropped', modifiers)
  }
}

Prevention

When it happens

Trigger: Calling push(range, 'keyword', ['static']) where 'static' is not in the tokenModifiers array given to the constructor; a server emitting a modifier absent from the client-built legend.

Common situations: Client legend built from an older spec while the server added new modifiers (e.g. 'defaultLibrary'); typos in modifier names; forgetting modifiers entirely in the legend object.

Related errors


AI-assisted analysis of neoclide/coc.nvim@50e974d969 (2026-08-31). Data as JSON: /api/errors/3939fca39ea4bc0f. Report an issue: GitHub.