neoclide/coc.nvim · error
Legend must be provided in constructor
Error message
Legend must be provided in constructor
What it means
_push requires a token legend: SemanticTokensBuilder must be constructed with { tokenTypes: [...], tokenModifiers: [...] } (or a default legend). If the builder was created without a legend, string token types cannot be mapped to numeric indices, so it throws this error.
Source
Thrown at src/model/semanticTokensBuilder.ts:79
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) {
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)!View on GitHub (pinned to 50e974d969)
Solutions
- Construct the builder with a legend: new SemanticTokensBuilder({ tokenTypes: ['keyword','string',...], tokenModifiers: ['readonly',...] })
- Or supply the same tokenTypes/tokenModifiers arrays your server declares in its SemanticTokensLegend
- Use the encoded overload (numeric tokenType) if you truly have no legend
Example fix
// before
const builder = new SemanticTokensBuilder()
// after
const builder = new SemanticTokensBuilder({ tokenTypes: ['keyword','string','number'], tokenModifiers: ['readonly','deprecated'] }) Defensive patterns
Strategy: validation
Validate before calling
if (!builder || !legend || !legend.tokenTypes?.length) {
throw new Error('SemanticTokensBuilder requires a legend')
} Type guard
function hasLegend(b: SemanticTokensBuilder): boolean {
return (b as any).legend !== undefined || (b as any)._hasLegend === true
} Try / catch
try {
builder.push(range, tokenType)
} catch (e) {
if (e.message.includes('Legend must be provided')) {
builder = new SemanticTokensBuilder({ tokenTypes: serverLegend.tokenTypes, tokenModifiers: serverLegend.tokenModifiers })
}
} Prevention
- Always construct SemanticTokensBuilder with the server's SemanticTokensLegend
- Never rely on default legends when writing custom providers
- Centralize legend construction in one module
When it happens
Trigger: Creating new SemanticTokensBuilder() with no legend and then calling push(range, 'keyword', ...) — the Range/string overload always requires a legend to translate the string tokenType.
Common situations: Following older examples that used the default vscode legend; forgetting the constructor argument when wiring a custom semantic tokens provider; upgrading coc.nvim where legend became required.
Related errors
- Illegal argument
- `tokenType` is not in the provided legend
- `tokenModifier` is not in the provided legend
- Command: ${command} not found
- name and doComplete required for createSource
AI-assisted analysis of neoclide/coc.nvim@50e974d969 (2026-08-31).
Data as JSON: /api/errors/82e37d1da8af7214.
Report an issue: GitHub.