{"record":{"id":"164945095747cde8","repo":"heygen-com/hyperframes","slug":"selector-matched-matches-length-elements-use-a","errorCode":null,"errorMessage":"Selector matched ${matches.length} elements; use a unique selector or --selector-index","messagePattern":"Selector matched (.+?) elements; use a unique selector or --selector-index","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/commands/media-treatment.ts","lineNumber":429,"sourceCode":"  }\n  return [];\n}\n\nfunction selectMediaElement(\n  source: string,\n  selector: string,\n  selectorIndex?: number,\n): { element: Element; selectorIndex: number; tag: \"img\" | \"video\" } {\n  const document = parseSourceDocument(source);\n  let matches: Element[];\n  try {\n    matches = queryIncludingTemplates(document, selector);\n  } catch {\n    throw new Error(`Invalid selector: ${selector}`);\n  }\n  if (matches.length === 0) throw new Error(`Selector did not match: ${selector}`);\n  if (selectorIndex === undefined && matches.length > 1) {\n    throw new Error(\n      `Selector matched ${matches.length} elements; use a unique selector or --selector-index`,\n    );\n  }\n\n  const resolvedIndex = selectorIndex ?? 0;\n  const element = matches[resolvedIndex];\n  if (!element) {\n    throw new Error(`--selector-index ${resolvedIndex} is outside ${matches.length} matches`);\n  }\n  const tag = element.tagName.toLowerCase();\n  if (tag !== \"img\" && tag !== \"video\") {\n    throw new Error(`Color grading requires an <img> or <video>; selector matched <${tag}>`);\n  }\n  return { element, selectorIndex: resolvedIndex, tag };\n}\n\nexport function applyMediaTreatmentToHtml(\n  source: string,","sourceCodeStart":411,"sourceCodeEnd":447,"githubUrl":"https://github.com/heygen-com/hyperframes/blob/c2996c8626135db5253519359d8a063d3bafad8d/packages/cli/src/commands/media-treatment.ts#L411-L447","documentation":"Thrown by selectMediaElement() in packages/cli/src/commands/media-treatment.ts:428. When a selector matches more than one element and --selector-index is not supplied, it refuses to pick the first silently (the code comment elsewhere calls out 'first-match-only sampling silently passes for siblings'). You must disambiguate.","triggerScenarios":"A selector like 'img', 'video', or '.media' that matches multiple elements in the composition, with no --selector-index provided.","commonSituations":"Common tag/class selectors; multiple media elements in one scene; refactoring introduced a second matching element; intended a specific one but used a generic selector.","solutions":["Use a more specific selector: add an id, a parent scope (e.g. '#scene1 img'), or a unique class.","Or pass --selector-index <n> to pick the nth match (0-based).","Run `hyperframes media-treatment --selector '<sel>' --dry-run --json` to see how many matches before writing."],"exampleFix":"# before -- ambiguous\nhyperframes media-treatment --selector 'img' --grading '{...}' --apply\n# after -- unique selector\nhyperframes media-treatment --selector '#hero' --grading '{...}' --apply\n# or by index\nhyperframes media-treatment --selector 'img' --selector-index 2 --grading '{...}' --apply","handlingStrategy":"validation","validationCode":"import { parseHTML } from 'linkedom';\n\nfunction selectorIsUnique(selector: string, source: string): boolean {\n  const { document } = parseHTML(source);\n  return document.querySelectorAll(selector).length === 1;\n}","typeGuard":null,"tryCatchPattern":"try {\n  selectMediaElement(source, selector);\n} catch (error) {\n  if (/Selector matched .* elements/.test(String(error))) {\n    // either narrow the selector or pass --selector-index\n    selectMediaElement(source, narrowerSelector);\n  } else throw error;\n}","preventionTips":["Prefer id-based or scoped selectors for uniqueness.","Pass --selector-index when you intentionally target one of several matches.","Use --dry-run --json to see match counts before writing."],"tags":["css","validation","media-treatment"],"backgroundTag":null,"analyzedSha":"c2996c8626135db5253519359d8a063d3bafad8d","analyzedAt":"2026-08-12T22:18:56.877Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}