neoclide/coc.nvim · error

Illegal argument

Error message

Illegal argument

What it means

SemanticTokensBuilder.push() supports only two documented overloads: (deltaLine, deltaStart, length, tokenType, tokenModifiers) with numeric tokenType, or (range, tokenType, tokenModifiers) with a Range and string tokenType. If the arguments match neither overload signature, the builder throws 'Illegal argument'.

Source

Thrown at src/model/semanticTokensBuilder.ts:74

   * Add another token. Use only when providing a legend.
   * @param range The range of the token. Must be single-line.
   * @param tokenType The token type.
   * @param tokenModifiers The token modifiers.
   */
  public push(range: Range, tokenType: string, tokenModifiers?: string[]): void
  public push(arg0: any, arg1: any, arg2: any, arg3?: any, arg4?: any): void {
    if (typeof arg0 === 'number' && typeof arg1 === 'number' && typeof arg2 === 'number' && typeof arg3 === 'number' && (typeof arg4 === 'number' || typeof arg4 === 'undefined')) {
      if (typeof arg4 === 'undefined') {
        arg4 = 0
      }
      // 1st overload
      return this._pushEncoded(arg0, arg1, arg2, arg3, arg4)
    }
    if (Range.is(arg0) && typeof arg1 === 'string' && isStrArrayOrUndefined(arg2)) {
      // 2nd overload
      return this._push(arg0, arg1, arg2)
    }
    throw new Error('Illegal argument')
  }

  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) {

View on GitHub (pinned to 50e974d969)

Solutions

  1. Use one overload consistently: push(line, startChar, length, tokenTypeIndex, modifiersBitmask) or push(range, 'keyword', ['readonly'])
  2. Ensure the tokenType is a number when using the encoded overload and a string when using the Range overload
  3. Check argument count: encoded overload needs exactly 5 args, Range overload needs 2-3
  4. Add a unit test covering each push overload used in your provider

Example fix

// before
builder.push(range, tokenTypeIndex) // mixed overload
// after
builder.push(range, legend.tokenTypes[tokenTypeIndex], []) // Range + string tokenType
Defensive patterns

Strategy: validation

Validate before calling

function isValidPushArgs(...args: any[]): boolean {
  if (args.length === 5 && typeof args[3] === 'number') return true
  if (Range.is(args[0]) && typeof args[1] === 'string' && (args.length === 2 || Array.isArray(args[2]))) return true
  return false
}

Type guard

function isRangeOverload(a: any): a is [Range, string, string[]?] {
  return Range.is(a[0]) && typeof a[1] === 'string' && (a[2] === undefined || Array.isArray(a[2]))
}

Try / catch

try {
  builder.push(range, tokenType, modifiers)
} catch (e) {
  if (e.message === 'Illegal argument') {
    console.error('push called with mismatched overload arguments', arguments)
  }
}

Prevention

When it happens

Trigger: Calling push with e.g. a numeric tokenType plus a Range, a string tokenType with numeric deltas, wrong argument counts (fewer than 3 or more than 5 args), or a non-string tokenType with a Range (typeof arg1 === 'string' fails).

Common situations: Mixing up the two overload styles during refactors; passing a LSP semantic token type index where a string is expected; migrating from vscode-languageserver builder API with different argument order.

Related errors


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