{"record":{"id":"c312e5c1ba834b3f","repo":"neoclide/coc.nvim","slug":"parent-placeholder-has-same-index-idx","errorCode":null,"errorMessage":"Parent placeholder has same index: ${idx}","messagePattern":"Parent placeholder has same index: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/snippets/parser.ts","lineNumber":431,"sourceCode":"    if (this.transform) {\n      ret.transform = this.transform.clone()\n    }\n    ret.id = this.id\n    ret.primary = this.primary\n    ret._children = this.children.map(child => {\n      let m = child.clone()\n      m.parent = ret\n      return m\n    })\n    return ret\n  }\n\n  public checkParentPlaceHolders(): void {\n    let idx = this.index\n    let p = this.parent\n    while (p != null && !(p instanceof TextmateSnippet)) {\n      if (p instanceof Placeholder && p.index == idx) {\n        throw new Error(`Parent placeholder has same index: ${idx}`)\n      }\n      p = p.parent\n    }\n  }\n}\n\nexport class Choice extends Marker {\n  private _index\n  constructor(index = 0) {\n    super()\n    this._index = index\n  }\n  public readonly options: Text[] = []\n\n  public appendChild(marker: Marker): this {\n    if (marker instanceof Text) {\n      marker.parent = this\n      this.options.push(marker)","sourceCodeStart":413,"sourceCodeEnd":449,"githubUrl":"https://github.com/neoclide/coc.nvim/blob/50e974d9692461a69147d5cab146a8d3e439abe4/src/snippets/parser.ts#L413-L449","documentation":"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.","triggerScenarios":"Parsing or programmatically building a snippet where a placeholder contains itself with the same index, e.g. '${1:${1:inner}}'.","commonSituations":"Hand-written or converted snippets (e.g. from other editors) with duplicated nested placeholder indices.","solutions":["Find the nested placeholder with the duplicate index in the snippet body.","Renumber the inner placeholder to a unique index.","Remove the redundant nesting if the text is identical.","Validate snippets in tests using snippetManager.resolveSnippet or parser before shipping."],"exampleFix":"// before\nlet snippet = 'class ${1:${1:Name}}'\n// after\nlet snippet = 'class ${1:${2:Name}}'","handlingStrategy":"validation","validationCode":"function validateSnippet(body: string): boolean {\n  // quick textual check: no placeholder directly nested with same index\n  return !/\\$\\{(\\d+):[^}]*\\$\\{\\1:/.test(body)\n}","typeGuard":"function isSnippetString(s: unknown): s is string {\n  return typeof s === 'string' && !/\\$\\{(\\d+):[^}]*\\$\\{\\1:/.test(s)\n}","tryCatchPattern":"try {\n  snippetManager.resolveSnippet(body)\n} catch (e) {\n  if (String(e.message).includes('Parent placeholder has same index')) fixDuplicateIndices(body)\n}","preventionTips":["Never reuse the same index in nested placeholders.","Run snippet strings through the parser in tests.","Auto-renumber placeholders when generating snippets programmatically.","Review snippets imported from other editors."],"tags":["snippets","parser","validation"],"backgroundTag":"invalid-snippet-placeholder","analyzedSha":"50e974d9692461a69147d5cab146a8d3e439abe4","analyzedAt":"2026-08-31T11:17:23.966Z","schemaVersion":2},"datasetVersion":"2026-09-01T08:17:40.651Z"}