neoclide/coc.nvim · error

Parent placeholder has same index: ${idx}

Error message

Parent placeholder has same index: ${idx}

What it means

checkParentPlaceHolders validates snippet marker nesting: a Placeholder must not have an ancestor Placeholder with the same index, since $1 inside $1 makes replacement semantics ambiguous. The snippet parser calls it after parsing to reject malformed snippet definitions.

Source

Thrown at src/snippets/parser.ts:431

    if (this.transform) {
      ret.transform = this.transform.clone()
    }
    ret.id = this.id
    ret.primary = this.primary
    ret._children = this.children.map(child => {
      let m = child.clone()
      m.parent = ret
      return m
    })
    return ret
  }

  public checkParentPlaceHolders(): void {
    let idx = this.index
    let p = this.parent
    while (p != null && !(p instanceof TextmateSnippet)) {
      if (p instanceof Placeholder && p.index == idx) {
        throw new Error(`Parent placeholder has same index: ${idx}`)
      }
      p = p.parent
    }
  }
}

export class Choice extends Marker {
  private _index
  constructor(index = 0) {
    super()
    this._index = index
  }
  public readonly options: Text[] = []

  public appendChild(marker: Marker): this {
    if (marker instanceof Text) {
      marker.parent = this
      this.options.push(marker)

View on GitHub (pinned to 50e974d969)

Solutions

  1. Find the nested placeholder with the duplicate index in the snippet body.
  2. Renumber the inner placeholder to a unique index.
  3. Remove the redundant nesting if the text is identical.
  4. Validate snippets in tests using snippetManager.resolveSnippet or parser before shipping.

Example fix

// before
let snippet = 'class ${1:${1:Name}}'
// after
let snippet = 'class ${1:${2:Name}}'
Defensive patterns

Strategy: validation

Validate before calling

function validateSnippet(body: string): boolean {
  // quick textual check: no placeholder directly nested with same index
  return !/\$\{(\d+):[^}]*\$\{\1:/.test(body)
}

Type guard

function isSnippetString(s: unknown): s is string {
  return typeof s === 'string' && !/\$\{(\d+):[^}]*\$\{\1:/.test(s)
}

Try / catch

try {
  snippetManager.resolveSnippet(body)
} catch (e) {
  if (String(e.message).includes('Parent placeholder has same index')) fixDuplicateIndices(body)
}

Prevention

When it happens

Trigger: Parsing or programmatically building a snippet where a placeholder contains itself with the same index, e.g. '${1:${1:inner}}'.

Common situations: Hand-written or converted snippets (e.g. from other editors) with duplicated nested placeholder indices.

Related errors


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